﻿#include "tetgen.h"

namespace Tetgen
{
	// Initialize all variables.
	tetgenbehavior::tetgenbehavior()
	{
		plc = false;
		psc = 0;
		refine = false;
		quality = 0;
		nobisect = 0;
		coarsen = 0;
		metric = 0;
		weighted = 0;
		brio_hilbert = 1;
		incrflip = 0;
		flipinsert = 0;
		varvolume = 0;
		fixedvolume = 0;
		noexact = 0;
		nostaticfilter = 0;
		insertaddpoints = 0;
		regionattrib = 0;
		conforming = 0;
		diagnose = 0;
		convex = 0;
		zeroindex = 0;

		facesout = 0;
		edgesout = 0;
		neighout = 0;
		voroout = 0;
		meditview = 0;
		vtkview = 0;

		nobound = 0;
		nonodewritten = 0;
		noelewritten = 0;
		nofacewritten = 0;
		noiterationnum = 0;
		nomergefacet = 0;
		nomergevertex = 0;
		nojettison = 0;

		reversetetori = 0;
		docheck = 0;
		quiet = false;
		verbose = 0;

		vertexperblock = 4092;
		tetrahedraperblock = 8188;
		shellfaceperblock = 4092;
		nobisect_param = 2;
		addsteiner_algo = 1;
		coarsen_param = 0;
		weighted_param = 0;
		fliplinklevel = -1; // No limit on linklevel.
		flipstarsize = -1;  // No limit on flip star size.
		fliplinklevelinc = 1;
		reflevel = 3;
		optscheme = 7;  // 1 & 2 & 4, // min_max_dihedral.
		optlevel = 2;
		delmaxfliplevel = 1;
		order = 1;
		steinerleft = -1;
		no_sort = 0;
		hilbert_order = 52; //-1;
		hilbert_limit = 8;
		brio_threshold = 64;
		brio_ratio = 0.125;
		facet_ang_tol = 179.9;
		maxvolume = -1.0;
		minratio = 2.0;
		minDihedral = 0.0; // 5.0; 
		optmaxdihedral = 165.00; // without -q, default is 179.0
		optminsmtdihed = 179.00; // without -q, default is 179.999
		optminslidihed = 179.00; // without -q, default is 179.999
		epsilon = 1.0e-8;
		minedgelength = 0.0;
		coarsen_percent = 1.0;
		object = TetInEnum::NODES;

		commandline[0] = '\0';
		infilename[0] = '\0';
		outfilename[0] = '\0';
		addinfilename[0] = '\0';
		bgmeshfilename[0] = '\0';
	}
	tetgenbehavior::~tetgenbehavior()
	{

	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// syntax()    Print list of command line switches.	//
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	void tetgenbehavior::syntax()
	{
		printf("  tetgen [-pYrq_Aa_miO_S_T_XMwcdzfenvgkJBNEFICQVh] input_file\n");
		printf("    -p  Tetrahedralizes a piecewise linear complex (PLC).\n");
		printf("    -Y  Preserves the input surface mesh (does not modify it).\n");
		printf("    -r  Reconstructs a previously generated mesh.\n");
		printf("    -q  Refines mesh (to improve mesh quality).\n");
		printf("    -R  Mesh coarsening (to reduce the mesh elements).\n");
		printf("    -A  Assigns attributes to tetrahedra in different regions.\n");
		printf("    -a  Applies a maximum tetrahedron volume constraint.\n");
		printf("    -m  Applies a mesh sizing function.\n");
		printf("    -i  Inserts a list of additional points.\n");
		printf("    -O  Specifies the level of mesh optimization.\n");
		printf("    -S  Specifies maximum number of added points.\n");
		printf("    -T  Sets a tolerance for coplanar test (default 1e-8).\n");
		printf("    -X  Suppresses use of exact arithmetic.\n");
		printf("    -M  No merge of coplanar facets or very close vertices.\n");
		printf("    -w  Generates weighted Delaunay (regular) triangulation.\n");
		printf("    -c  Retains the convex hull of the PLC.\n");
		printf("    -d  Detects self-intersections of facets of the PLC.\n");
		printf("    -z  Numbers all output items starting from zero.\n");
		printf("    -f  Outputs all faces to .face file.\n");
		printf("    -e  Outputs all edges to .edge file.\n");
		printf("    -n  Outputs tetrahedra neighbors to .neigh file.\n");
		printf("    -v  Outputs Voronoi diagram to files.\n");
		printf("    -g  Outputs mesh to .mesh file for viewing by Medit.\n");
		printf("    -k  Outputs mesh to .vtk file for viewing by Paraview.\n");
		printf("    -J  No jettison of unused vertices from output .node file.\n");
		printf("    -B  Suppresses output of boundary information.\n");
		printf("    -N  Suppresses output of .node file.\n");
		printf("    -E  Suppresses output of .ele file.\n");
		printf("    -F  Suppresses output of .face and .edge file.\n");
		printf("    -I  Suppresses mesh iteration numbers.\n");
		printf("    -C  Checks the consistency of the final mesh.\n");
		printf("    -Q  Quiet:  No terminal output except errors.\n");
		printf("    -V  Verbose:  Detailed information, more terminal output.\n");
		printf("    -h  Help:  A brief instruction for using TetGen.\n");
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// usage()    Print a brief instruction for using TetGen.                    //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	void tetgenbehavior::usage()
	{
		printf("TetGen\n");
		printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
		printf("Triangulator\n");
		printf("Version 1.5\n");
		printf("November 4, 2013\n");
		printf("\n");
		printf("What Can TetGen Do?\n");
		printf("\n");
		printf("  TetGen generates Delaunay tetrahedralizations, constrained\n");
		printf("  Delaunay tetrahedralizations, and quality tetrahedral meshes.\n");
		printf("\n");
		printf("Command Line Syntax:\n");
		printf("\n");
		printf("  Below is the basic command line syntax of TetGen with a list of ");
		printf("short\n");
		printf("  descriptions. Underscores indicate that numbers may optionally\n");
		printf("  follow certain switches.  Do not leave any space between a ");
		printf("switch\n");
		printf("  and its numeric parameter.  \'input_file\' contains input data\n");
		printf("  depending on the switches you supplied which may be a ");
		printf("  piecewise\n");
		printf("  linear complex or a list of nodes.  File formats and detailed\n");
		printf("  description of command line switches are found in user's ");
		printf("manual.\n");
		printf("\n");
		syntax();
		printf("\n");
		printf("Examples of How to Use TetGen:\n");
		printf("\n");
		printf("  \'tetgen object\' reads vertices from object.node, and writes ");
		printf("their\n  Delaunay tetrahedralization to object.1.node, ");
		printf("object.1.ele\n  (tetrahedra), and object.1.face");
		printf(" (convex hull faces).\n");
		printf("\n");
		printf("  \'tetgen -p object\' reads a PLC from object.poly or object.");
		printf("smesh (and\n  possibly object.node) and writes its constrained ");
		printf("Delaunay\n  tetrahedralization to object.1.node, object.1.ele, ");
		printf("object.1.face,\n");
		printf("  (boundary faces) and object.1.edge (boundary edges).\n");
		printf("\n");
		printf("  \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
		printf("  object.smesh (and possibly object.node), generates a mesh ");
		printf("whose\n  tetrahedra have radius-edge ratio smaller than 1.414 and ");
		printf("have volume\n  of 0.1 or less, and writes the mesh to ");
		printf("object.1.node, object.1.ele,\n  object.1.face, and object.1.edge\n");
		printf("\n");
		printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
		exit(0);
	}

	///////////////////////////////////////////////////////////////////////////////
	// 解析tetgen命令行输入参数                                                                          //
	// parse_commandline()    Read the command line, identify switches, and set  //
	//                        up options and file names.                         //
	//                                                                           //
	// 'argc' and 'argv' are the same parameters passed to the function main()   //
	// of a C/C++ program. They together represent the command line user invoked //
	// from an environment in which TetGen is running.                           //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenbehavior::parse_commandline(int argc, char **argv)
	{
		int startindex = 0;
		int increment;
		int meshnumber;
		int i, j, k;
		char workstring[1024];

		// First determine the input style of the switches.
		if (argc == 0)
		{
			startindex = 0;                    // Switches are given without a dash.
			argc = 1;                    // For running the following for-loop once.
			commandline[0] = '\0';
		}
		else
		{
			startindex = 1;
			strcpy(commandline, argv[0]);
			strcat(commandline, " ");
		}

		for (i = startindex; i < argc; i++)
		{
			// Remember the command line for output.
			strcat(commandline, argv[i]);
			strcat(commandline, " ");

			if (startindex == 1)
			{
				// Is this string a filename?
				if (argv[i][0] != '-')
				{
					strncpy(infilename, argv[i], 1024 - 1);
					infilename[1024 - 1] = '\0';
					continue;
				}
			}

			// Parse the individual switch from the string.
			for (j = startindex; argv[i][j] != '\0'; j++) {
				if (argv[i][j] == 'p') {
					plc = true;
					if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
						(argv[i][j + 1] == '.')) {
						k = 0;
						while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.')) {
							j++;
							workstring[k] = argv[i][j];
							k++;
						}
						workstring[k] = '\0';
						facet_ang_tol = (REAL)strtod(workstring, (char **)NULL);
					}
				}
				else if (argv[i][j] == 's') {
					psc = 1;
				}
				else if (argv[i][j] == 'Y') {
					nobisect = 1;
					if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
						nobisect_param = (argv[i][j + 1] - '0');
						j++;
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
							addsteiner_algo = (argv[i][j + 1] - '0');
							j++;
						}
					}
				}
				else if (argv[i][j] == 'r') {
					refine = true;
				}
				else if (argv[i][j] == 'q') {
					quality = 1;
					if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
						(argv[i][j + 1] == '.')) {
						k = 0;
						while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.')) {
							j++;
							workstring[k] = argv[i][j];
							k++;
						}
						workstring[k] = '\0';
						minratio = (REAL)strtod(workstring, (char **)NULL);
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.')) {
							k = 0;
							while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
								(argv[i][j + 1] == '.')) {
								j++;
								workstring[k] = argv[i][j];
								k++;
							}
							workstring[k] = '\0';
							minDihedral = (REAL)strtod(workstring, (char **)NULL);
						}
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.')) {
							k = 0;
							while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
								(argv[i][j + 1] == '.')) {
								j++;
								workstring[k] = argv[i][j];
								k++;
							}
							workstring[k] = '\0';
							optmaxdihedral = (REAL)strtod(workstring, (char **)NULL);
						}
					}
				}
				else if (argv[i][j] == 'R') {
					coarsen = 1;
					if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
						coarsen_param = (argv[i][j + 1] - '0');
						j++;
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.')) {
							k = 0;
							while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
								(argv[i][j + 1] == '.')) {
								j++;
								workstring[k] = argv[i][j];
								k++;
							}
							workstring[k] = '\0';
							coarsen_percent = (REAL)strtod(workstring, (char **)NULL);
						}
					}
				}
				else if (argv[i][j] == 'w') {
					weighted = 1;
					if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
						weighted_param = (argv[i][j + 1] - '0');
						j++;
					}
				}
				else if (argv[i][j] == 'b') {
					// -b(brio_threshold/brio_ratio/hilbert_limit/hilbert_order)
					brio_hilbert = 1;
					if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
						(argv[i][j + 1] == '.')) {
						k = 0;
						while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.')) {
							j++;
							workstring[k] = argv[i][j];
							k++;
						}
						workstring[k] = '\0';
						brio_threshold = (int)strtol(workstring, (char **)&workstring, 0);
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.')) {
							k = 0;
							while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
								(argv[i][j + 1] == '.')) {
								j++;
								workstring[k] = argv[i][j];
								k++;
							}
							workstring[k] = '\0';
							brio_ratio = (REAL)strtod(workstring, (char **)NULL);
						}
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
							k = 0;
							while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
								(argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
								j++;
								workstring[k] = argv[i][j];
								k++;
							}
							workstring[k] = '\0';
							hilbert_limit = (int)strtol(workstring, (char **)&workstring, 0);
						}
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
							k = 0;
							while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
								(argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
								j++;
								workstring[k] = argv[i][j];
								k++;
							}
							workstring[k] = '\0';
							hilbert_order = static_cast<int>(strtod(workstring, (char **)NULL));
						}
					}
					if (brio_threshold == 0) { // -b0
						brio_hilbert = 0; // Turn off BRIO-Hilbert sorting. 
					}
					if (brio_ratio >= 1.0) { // -b/1
						no_sort = 1;
						brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
					}
				}
				else if (argv[i][j] == 'l') {
					incrflip = 1;
				}
				else if (argv[i][j] == 'L') {
					flipinsert = 1;
				}
				else if (argv[i][j] == 'm') {
					metric = 1;
				}
				else if (argv[i][j] == 'a') {
					if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
						(argv[i][j + 1] == '.')) {
						fixedvolume = 1;
						k = 0;
						while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
							(argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
							j++;
							workstring[k] = argv[i][j];
							k++;
						}
						workstring[k] = '\0';
						maxvolume = (REAL)strtod(workstring, (char **)NULL);
					}
					else {
						varvolume = 1;
					}
				}
				else if (argv[i][j] == 'A') {
					regionattrib = 1;
				}
				else if (argv[i][j] == 'D') {
					conforming = 1;
					if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) {
						reflevel = (argv[i][j + 1] - '1') + 1;
						j++;
					}
				}
				else if (argv[i][j] == 'i') {
					insertaddpoints = 1;
				}
				else if (argv[i][j] == 'd') {
					diagnose = 1;
				}
				else if (argv[i][j] == 'c') {
					convex = 1;
				}
				else if (argv[i][j] == 'M') {
					nomergefacet = 1;
					nomergevertex = 1;
					if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
						nomergefacet = (argv[i][j + 1] - '0');
						j++;
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
							nomergevertex = (argv[i][j + 1] - '0');
							j++;
						}
					}
				}
				else if (argv[i][j] == 'X') {
					if (argv[i][j + 1] == '1') {
						nostaticfilter = 1;
						j++;
					}
					else {
						noexact = 1;
					}
				}
				else if (argv[i][j] == 'z') {
					zeroindex = 1;
				}
				else if (argv[i][j] == 'f') {
					facesout++;
				}
				else if (argv[i][j] == 'e') {
					edgesout++;
				}
				else if (argv[i][j] == 'n') {
					neighout++;
				}
				else if (argv[i][j] == 'v') {
					voroout = 1;
				}
				else if (argv[i][j] == 'g') {
					meditview = 1;
				}
				else if (argv[i][j] == 'k') {
					vtkview = 1;
				}
				else if (argv[i][j] == 'J') {
					nojettison = 1;
				}
				else if (argv[i][j] == 'B') {
					nobound = 1;
				}
				else if (argv[i][j] == 'N') {
					nonodewritten = 1;
				}
				else if (argv[i][j] == 'E') {
					noelewritten = 1;
				}
				else if (argv[i][j] == 'F') {
					nofacewritten = 1;
				}
				else if (argv[i][j] == 'I') {
					noiterationnum = 1;
				}
				else if (argv[i][j] == 'S') {
					if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
						(argv[i][j + 1] == '.')) {
						k = 0;
						while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
							(argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
							j++;
							workstring[k] = argv[i][j];
							k++;
						}
						workstring[k] = '\0';
						steinerleft = (int)strtol(workstring, (char **)NULL, 0);
					}
				}
				else if (argv[i][j] == 'o') {
					if (argv[i][j + 1] == '2') {
						order = 2;
						j++;
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.')) {
							k = 0;
							while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
								(argv[i][j + 1] == '.')) {
								j++;
								workstring[k] = argv[i][j];
								k++;
							}
							workstring[k] = '\0';
							optmaxdihedral = (REAL)strtod(workstring, (char **)NULL);
						}
					}
				}
				else if (argv[i][j] == 'O') {
					if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
						optlevel = (argv[i][j + 1] - '0');
						j++;
					}
					if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
						j++;
						if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) {
							optscheme = (argv[i][j + 1] - '0');
							j++;
						}
					}
				}
				else if (argv[i][j] == 'T') {
					if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
						(argv[i][j + 1] == '.')) {
						k = 0;
						while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
							(argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
							j++;
							workstring[k] = argv[i][j];
							k++;
						}
						workstring[k] = '\0';
						epsilon = (REAL)strtod(workstring, (char **)NULL);
					}
				}
				else if (argv[i][j] == 'R') {
					reversetetori = 1;
				}
				else if (argv[i][j] == 'C') {
					docheck++;
				}
				else if (argv[i][j] == 'Q') {
					quiet = true;
				}
				else if (argv[i][j] == 'V') {
					verbose++;
				}
				else if (argv[i][j] == 'x') {
					if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
						(argv[i][j + 1] == '.')) {
						k = 0;
						while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
							(argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
							(argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
							j++;
							workstring[k] = argv[i][j];
							k++;
						}
						workstring[k] = '\0';
						tetrahedraperblock = (int)strtol(workstring, (char **)NULL, 0);
						if (tetrahedraperblock > 8188) {
							vertexperblock = tetrahedraperblock / 2;
							shellfaceperblock = vertexperblock / 2;
						}
						else {
							tetrahedraperblock = 8188;
						}
					}
				}
				else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
					(argv[i][j] == '?')) {
					usage();
				}
				else {
					printf("Warning:  Unknown switch -%c.\n", argv[i][j]);
				}
			}
		}

		if (startindex == 0) 
		{
			// Set a temporary filename for debugging output.
			strcpy(infilename, "tetgen-tmpfile");
		}
		else 
		{
			if (infilename[0] == '\0') 
			{
				// No input file name. Print the syntax and exit.
				syntax();
				exit(0);
			}
			// Recognize the object from file extension if it is available.
			if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) 
			{
				infilename[strlen(infilename) - 5] = '\0';
				object = TetInEnum::NODES;
			}
			else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) 
			{
				infilename[strlen(infilename) - 5] = '\0';
				object = TetInEnum::POLY;
				plc = true;
			}
			else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) 
			{
				infilename[strlen(infilename) - 6] = '\0';
				object = TetInEnum::POLY;
				plc = true;
			}
			else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) 
			{
				infilename[strlen(infilename) - 4] = '\0';
				object = TetInEnum::OFF;
				plc = true;
			}
			else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) 
			{
				infilename[strlen(infilename) - 4] = '\0';
				object = TetInEnum::PLY;
				plc = true;
			}
			else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) 
			{
				infilename[strlen(infilename) - 4] = '\0';
				object = TetInEnum::STL;
				plc = true;
			}
			else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) 
			{
				infilename[strlen(infilename) - 5] = '\0';
				object = TetInEnum::MEDIT;
				if (!refine) plc = true;
			}
			else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) 
			{
				infilename[strlen(infilename) - 4] = '\0';
				object = TetInEnum::VTK;
				plc = true;
			}
			else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) 
			{
				infilename[strlen(infilename) - 4] = '\0';
				object = TetInEnum::MESH;
				refine = true;
			}
		}

		if (nobisect && (!plc && !refine)) { // -Y
			plc = true; // Default -p option.
		}
		if (quality && (!plc && !refine)) { // -q
			plc = true; // Default -p option.
		}
		if (diagnose && !plc) { // -d
			plc = true;
		}
		if (refine && !quality) { // -r only
			// Reconstruct a mesh, no mesh optimization.
			optlevel = 0;
		}
		if (insertaddpoints && (optlevel == 0)) { // with -i option
			optlevel = 2;
		}
		if (coarsen && (optlevel == 0)) { // with -R option
			optlevel = 2;
		}

		// Detect improper combinations of switches.
		if ((refine || plc) && weighted) {
			printf("Error:  Switches -w cannot use together with -p or -r.\n");
			return false;
		}

		if (convex) { // -c
			if (plc && !regionattrib) {
				// -A (region attribute) is needed for marking exterior tets (-1).
				regionattrib = 1;
			}
		}

		// Note: -A must not used together with -r option. 
		// Be careful not to add an extra attribute to each element unless the
		//   input supports it (PLC in, but not refining a preexisting mesh).
		if (refine || !plc) {
			regionattrib = 0;
		}
		// Be careful not to allocate space for element area constraints that 
		//   will never be assigned any value (other than the default -1.0).
		if (!refine && !plc) {
			varvolume = 0;
		}
		// If '-a' or '-aa' is in use, enable '-q' option too.
		if (fixedvolume || varvolume) {
			if (quality == 0) {
				quality = 1;
				if (!plc && !refine) {
					plc = true; // enable -p.
				}
			}
		}
		// No user-specified dihedral angle bound. Use default ones.
		if (!quality) {
			if (optmaxdihedral < 179.0) {
				if (nobisect) {  // with -Y option
					optmaxdihedral = 179.0;
				}
				else { // -p only
					optmaxdihedral = 179.999;
				}
			}
			if (optminsmtdihed < 179.999) {
				optminsmtdihed = 179.999;
			}
			if (optminslidihed < 179.999) {
				optminslidihed = 179.999;
			}
		}

		increment = 0;
		strcpy(workstring, infilename);
		j = 1;
		while (workstring[j] != '\0') {
			if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
				increment = j + 1;
			}
			j++;
		}
		meshnumber = 0;
		if (increment > 0) {
			j = increment;
			do {
				if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
					meshnumber = meshnumber * 10 + (int)(workstring[j] - '0');
				}
				else {
					increment = 0;
				}
				j++;
			} while (workstring[j] != '\0');
		}
		if (noiterationnum) {
			strcpy(outfilename, infilename);
		}
		else if (increment == 0) {
			strcpy(outfilename, infilename);
			strcat(outfilename, ".1");
		}
		else {
			workstring[increment] = '%';
			workstring[increment + 1] = 'd';
			workstring[increment + 2] = '\0';
			sprintf(outfilename, workstring, meshnumber + 1);
		}
		// Additional input file name has the end ".a".
		strcpy(addinfilename, infilename);
		strcat(addinfilename, ".a");
		// Background filename has the form "*.b.ele", "*.b.node", ...
		strcpy(bgmeshfilename,infilename);
		strcat(bgmeshfilename, ".b");

		return true;
	}
	bool tetgenbehavior::parse_commandline(char *switches)
	{
		return parse_commandline(0, &switches);
	}

	bool tetgenbehavior::Refine() const
	{
		return refine;
	}

	bool tetgenbehavior::Quiet() const
	{
		return quiet;
	}

	bool tetgenbehavior::Plc() const
	{
		return plc;
	}

	void tetgenbehavior::setPlc(bool val)
	{
		plc = val;
	}

	REAL tetgenbehavior::MinDihedral() const
	{
		return minDihedral;
	}

	REAL tetgenbehavior::MaxVolume() const
	{
		return maxvolume;
	}

	REAL tetgenbehavior::MinRatio() const
	{
		return minratio;
	}

	void tetgenbehavior::setMinDihedral(double val)
	{
		minDihedral = val;
	}

	void tetgenbehavior::setMaxVolume(double val)
	{
		maxvolume = val;
	}

	void tetgenbehavior::setMinRatio(double val)
	{
		minratio = val;
	}

	void tetgenbehavior::setDefaultOption()
	{
		plc = true;				//读入.poly文件
		quality = 1;			//进行网格划分，而不是细化
		nobisect= 1;			//不改变边界网格

		maxvolume = 1000;	//最大单元体积
		minratio = 1.2;		//最大径边比
		minDihedral = 20;	//最小二面角

		object = TetInEnum::POLY;

		//nobound = 1;
		//nonodewritten = 1;
		//noelewritten = 1;
		//nofacewritten =1;
	}

	void tetgenbehavior::copyFileName(const tetgenbehavior & b)
	{
		strcpy(commandline, b.commandline);
		strcpy(infilename, b.infilename);
		strcpy(outfilename, b.outfilename);
		strcpy(addinfilename, b.addinfilename);
		strcpy(bgmeshfilename, b.bgmeshfilename);
	}

	// Constructor & destructor.
	tetgenio::tetgenio()
	{
		firstnumber = 0;
		mesh_dim = 3;
		useindex = true;

		pointlist = (REAL *)NULL;
		pointattributelist = (REAL *)NULL;
		pointmtrlist = (REAL *)NULL;
		pointmarkerlist = (int *)NULL;
		pointparamlist = (pointparam *)NULL;
		numberofpoints = 0;
		numberofpointattributes = 0;
		numberofpointmtrs = 0;

		tetrahedronlist = (int *)NULL;
		tetrahedronattributelist = (REAL *)NULL;
		tetrahedronvolumelist = (REAL *)NULL;
		neighborlist = (int *)NULL;
		numberoftetrahedra = 0;
		numberofcorners = 4;
		numberoftetrahedronattributes = 0;

		trifacelist = (int *)NULL;
		trifacemarkerlist = (int *)NULL;
		o2facelist = (int *)NULL;
		adjtetlist = (int *)NULL;
		numberoftrifaces = 0;

		edgelist = (int *)NULL;
		edgemarkerlist = (int *)NULL;
		o2edgelist = (int *)NULL;
		edgeadjtetlist = (int *)NULL;
		numberofedges = 0;

		facetlist = (facet *)NULL;
		facetmarkerlist = (int *)NULL;
		numberoffacets = 0;

		holelist = (REAL *)NULL;
		numberofholes = 0;

		regionlist = (REAL *)NULL;
		numberofregions = 0;

		facetconstraintlist = (REAL *)NULL;
		numberoffacetconstraints = 0;
		segmentconstraintlist = (REAL *)NULL;
		numberofsegmentconstraints = 0;


		vpointlist = (REAL *)NULL;
		vedgelist = (voroedge *)NULL;
		vfacetlist = (vorofacet *)NULL;
		vcelllist = (int **)NULL;
		numberofvpoints = 0;
		numberofvedges = 0;
		numberofvfacets = 0;
		numberofvcells = 0;

		tetunsuitable = NULL;

		geomhandle = NULL;
		getvertexparamonedge = NULL;
		getsteineronedge = NULL;
		getvertexparamonface = NULL;
		getedgesteinerparamonface = NULL;
		getsteineronface = NULL;
	}
	tetgenio::~tetgenio()
	{
		int i, j;

		if (pointlist != (REAL *)NULL)
		{
			delete[] pointlist;
		}
		if (pointattributelist != (REAL *)NULL)
		{
			delete[] pointattributelist;
		}
		if (pointmtrlist != (REAL *)NULL)
		{
			delete[] pointmtrlist;
		}
		if (pointmarkerlist != (int *)NULL)
		{
			delete[] pointmarkerlist;
		}
		if (pointparamlist != (pointparam *)NULL)
		{
			delete[] pointparamlist;
		}

		if (tetrahedronlist != (int *)NULL)
		{
			delete[] tetrahedronlist;
		}
		if (tetrahedronattributelist != (REAL *)NULL)
		{
			delete[] tetrahedronattributelist;
		}
		if (tetrahedronvolumelist != (REAL *)NULL)
		{
			delete[] tetrahedronvolumelist;
		}
		if (neighborlist != (int *)NULL)
		{
			delete[] neighborlist;
		}

		if (trifacelist != (int *)NULL) {
			delete[] trifacelist;
		}
		if (trifacemarkerlist != (int *)NULL) {
			delete[] trifacemarkerlist;
		}
		if (o2facelist != (int *)NULL) {
			delete[] o2facelist;
		}
		if (adjtetlist != (int *)NULL) {
			delete[] adjtetlist;
		}

		if (edgelist != (int *)NULL) {
			delete[] edgelist;
		}
		if (edgemarkerlist != (int *)NULL) {
			delete[] edgemarkerlist;
		}
		if (o2edgelist != (int *)NULL) {
			delete[] o2edgelist;
		}
		if (edgeadjtetlist != (int *)NULL) {
			delete[] edgeadjtetlist;
		}

		if (facetlist != (facet *)NULL) {
			facet *f;
			polygon *p;
			for (i = 0; i < numberoffacets; i++) {
				f = &facetlist[i];
				for (j = 0; j < f->numberofpolygons; j++) {
					p = &f->polygonlist[j];
					delete[] p->vertexlist;
				}
				delete[] f->polygonlist;
				if (f->holelist != (REAL *)NULL) {
					delete[] f->holelist;
				}
			}
			delete[] facetlist;
		}
		if (facetmarkerlist != (int *)NULL) {
			delete[] facetmarkerlist;
		}

		if (holelist != (REAL *)NULL) {
			delete[] holelist;
		}
		if (regionlist != (REAL *)NULL) {
			delete[] regionlist;
		}
		if (facetconstraintlist != (REAL *)NULL) {
			delete[] facetconstraintlist;
		}
		if (segmentconstraintlist != (REAL *)NULL) {
			delete[] segmentconstraintlist;
		}
		if (vpointlist != (REAL *)NULL) {
			delete[] vpointlist;
		}
		if (vedgelist != (voroedge *)NULL) {
			delete[] vedgelist;
		}
		if (vfacetlist != (vorofacet *)NULL) {
			for (i = 0; i < numberofvfacets; i++) {
				delete[] vfacetlist[i].elist;
			}
			delete[] vfacetlist;
		}
		if (vcelllist != (int **)NULL) {
			for (i = 0; i < numberofvcells; i++) {
				delete[] vcelllist[i];
			}
			delete[] vcelllist;
		}
	}


	void tetgenio::init(polygon* p)
	{
		p->vertexlist = (int *)NULL;
		p->numberofvertices = 0;
	}

	void tetgenio::init(facet* f)
	{
		f->polygonlist = (polygon *)NULL;
		f->numberofpolygons = 0;
		f->holelist = (REAL *)NULL;
		f->numberofholes = 0;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_node_call()    Read a list of points from a file.                    //
	//                                                                           //
	// 'infile' is the file handle contains the node list.  It may point to a    //
	// .node, or .poly or .smesh file. 'markers' indicates each node contains an //
	// additional marker (integer) or not. 'uvflag' indicates each node contains //
	// u,v coordinates or not. It is reuqired by a PSC. 'infilename' is the name //
	// of the file being read,  it is only used in error messages.               //
	//                                                                           //
	// The 'firstnumber' (0 or 1) is automatically determined by the number of   //
	// the first index of the first point.                                       //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_node_call(FILE* infile, int markers, int uvflag,char* infilename)
	{
		char inputline[INPUTLINESIZE];
		char *stringptr;
		REAL x, y, z, attrib;
		int firstnode, currentmarker;
		int index, attribindex;
		int i, j;

		// Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
		pointlist = new REAL[numberofpoints * 3];
		if (pointlist == (REAL *)NULL) {
			exit(1);
		}
		if (numberofpointattributes > 0) {
			pointattributelist = new REAL[numberofpoints * numberofpointattributes];
			if (pointattributelist == (REAL *)NULL) {
				exit(1);
			}
		}
		if (markers) {
			pointmarkerlist = new int[numberofpoints];
			if (pointmarkerlist == (int *)NULL) {
				exit(1);
			}
		}
		if (uvflag) {
			pointparamlist = new pointparam[numberofpoints];
			if (pointparamlist == NULL) {
				exit(1);
			}
		}

		// Read the point section.
		index = 0;
		attribindex = 0;
		for (i = 0; i < numberofpoints; i++) {
			stringptr = readnumberline(inputline, infile, infilename);
			if (useindex) {
				if (i == 0) {
					firstnode = (int)strtol(stringptr, &stringptr, 0);
					if ((firstnode == 0) || (firstnode == 1)) {
						firstnumber = firstnode;
					}
				}
				stringptr = findnextnumber(stringptr);
			} // if (useindex)
			if (*stringptr == '\0') {
				printf("Error:  Point %d has no x coordinate.\n", firstnumber + i);
				break;
			}
			x = (REAL)strtod(stringptr, &stringptr);
			stringptr = findnextnumber(stringptr);
			if (*stringptr == '\0') {
				printf("Error:  Point %d has no y coordinate.\n", firstnumber + i);
				break;
			}
			y = (REAL)strtod(stringptr, &stringptr);
			if (mesh_dim == 3) {
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  Point %d has no z coordinate.\n", firstnumber + i);
					break;
				}
				z = (REAL)strtod(stringptr, &stringptr);
			}
			else {
				z = 0.0; // mesh_dim == 2;
			}
			pointlist[index++] = x;
			pointlist[index++] = y;
			pointlist[index++] = z;
			// Read the point attributes.
			for (j = 0; j < numberofpointattributes; j++) {
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					attrib = 0.0;
				}
				else {
					attrib = (REAL)strtod(stringptr, &stringptr);
				}
				pointattributelist[attribindex++] = attrib;
			}
			if (markers) {
				// Read a point marker.
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					currentmarker = 0;
				}
				else {
					currentmarker = (int)strtol(stringptr, &stringptr, 0);
				}
				pointmarkerlist[i] = currentmarker;
			}
			if (uvflag) {
				// Read point paramteters.
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  Point %d has no uv[0].\n", firstnumber + i);
					break;
				}
				pointparamlist[i].uv[0] = (REAL)strtod(stringptr, &stringptr);
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  Point %d has no uv[1].\n", firstnumber + i);
					break;
				}
				pointparamlist[i].uv[1] = (REAL)strtod(stringptr, &stringptr);
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  Point %d has no tag.\n", firstnumber + i);
					break;
				}
				pointparamlist[i].tag = (int)strtol(stringptr, &stringptr, 0);
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  Point %d has no type.\n", firstnumber + i);
					break;
				}
				pointparamlist[i].type = (int)strtol(stringptr, &stringptr, 0);
				if ((pointparamlist[i].type < 0) || (pointparamlist[i].type > 2)) {
					printf("Error:  Point %d has an invalid type.\n", firstnumber + i);
					break;
				}
			}
		}
		if (i < numberofpoints) {
			// Failed to read points due to some error.
			delete[] pointlist;
			pointlist = (REAL *)NULL;
			if (markers) {
				delete[] pointmarkerlist;
				pointmarkerlist = (int *)NULL;
			}
			if (numberofpointattributes > 0) {
				delete[] pointattributelist;
				pointattributelist = (REAL *)NULL;
			}
			if (uvflag) {
				delete[] pointparamlist;
				pointparamlist = NULL;
			}
			numberofpoints = 0;
			return false;
		}
		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_node()    Load a list of points from a .node file.                   //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_node(const string& fname)
	{
		FILE *infile;
		char innodefilename[FILENAMESIZE];
		char inputline[INPUTLINESIZE];
		char *stringptr;
		bool okflag;
		int markers;
		int uvflag; // for psc input.

		// Assembling the actual file names we want to open.
		strcpy(innodefilename, fname.c_str());
		strcat(innodefilename, ".node");

		// Try to open a .node file.
		infile = fopen(innodefilename, "r");
		if (infile == (FILE *)NULL) {
			printf("  Cannot access file %s.\n", innodefilename);
			return false;
		}
		printf("Opening %s.\n", innodefilename);

		// Set initial flags.
		mesh_dim = 3;
		numberofpointattributes = 0;  // no point attribute.
		markers = 0;  // no boundary marker.
		uvflag = 0; // no uv parameters (required by a PSC). 

		// Read the first line of the file.
		stringptr = readnumberline(inputline, infile, innodefilename);
		// Does this file contain an index column?
		stringptr = strstr(inputline, "rbox");
		if (stringptr == NULL) {
			// Read number of points, number of dimensions, number of point
			//   attributes, and number of boundary markers. 
			stringptr = inputline;
			numberofpoints = (int)strtol(stringptr, &stringptr, 0);
			stringptr = findnextnumber(stringptr);
			if (*stringptr != '\0') {
				mesh_dim = (int)strtol(stringptr, &stringptr, 0);
			}
			stringptr = findnextnumber(stringptr);
			if (*stringptr != '\0') {
				numberofpointattributes = (int)strtol(stringptr, &stringptr, 0);
			}
			stringptr = findnextnumber(stringptr);
			if (*stringptr != '\0') {
				markers = (int)strtol(stringptr, &stringptr, 0);
			}
			stringptr = findnextnumber(stringptr);
			if (*stringptr != '\0') {
				uvflag = (int)strtol(stringptr, &stringptr, 0);
			}
		}
		else {
			// It is a rbox (qhull) input file.
			stringptr = inputline;
			// Get the dimension.
			mesh_dim = (int)strtol(stringptr, &stringptr, 0);
			// Get the number of points.
			stringptr = readnumberline(inputline, infile, innodefilename);
			numberofpoints = (int)strtol(stringptr, &stringptr, 0);
			// There is no index column.
			useindex = false;
		}

		// Load the list of nodes.
		okflag = load_node_call(infile, markers, uvflag, innodefilename);

		fclose(infile);
		return okflag;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_edge()    Load a list of edges from a .edge file.                    //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_edge(char* filebasename)
	{
		FILE *infile;
		char inedgefilename[FILENAMESIZE];
		char inputline[INPUTLINESIZE];
		char *stringptr;
		int markers, corner;
		int index;
		int i, j;

		strcpy(inedgefilename, filebasename);
		strcat(inedgefilename, ".edge");

		infile = fopen(inedgefilename, "r");
		if (infile != (FILE *)NULL) {
			printf("Opening %s.\n", inedgefilename);
		}
		else {
			//printf("  Cannot access file %s.\n", inedgefilename);
			return false;
		}

		// Read number of boundary edges.
		stringptr = readnumberline(inputline, infile, inedgefilename);
		numberofedges = (int)strtol(stringptr, &stringptr, 0);
		if (numberofedges > 0) {
			edgelist = new int[numberofedges * 2];
			if (edgelist == (int *)NULL) {
				exit(1);
			}
			stringptr = findnextnumber(stringptr);
			if (*stringptr == '\0') {
				markers = 0;  // Default value.
			}
			else {
				markers = (int)strtol(stringptr, &stringptr, 0);
			}
			if (markers > 0) {
				edgemarkerlist = new int[numberofedges];
			}
		}

		// Read the list of edges.
		index = 0;
		for (i = 0; i < numberofedges; i++) {
			// Read edge index and the edge's two endpoints.
			stringptr = readnumberline(inputline, infile, inedgefilename);
			for (j = 0; j < 2; j++) {
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  Edge %d is missing vertex %d in %s.\n",
						i + firstnumber, j + 1, inedgefilename);
					exit(1);
				}
				corner = (int)strtol(stringptr, &stringptr, 0);
				if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
					printf("Error:  Edge %d has an invalid vertex index.\n",
						i + firstnumber);
					exit(1);
				}
				edgelist[index++] = corner;
			}
			if (numberofcorners == 10) {
				// Skip an extra vertex (generated by a previous -o2 option).
				stringptr = findnextnumber(stringptr);
			}
			// Read the edge marker if it has.
			if (markers) {
				stringptr = findnextnumber(stringptr);
				edgemarkerlist[i] = (int)strtol(stringptr, &stringptr, 0);
			}
		}

		fclose(infile);
		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_face()    Load a list of faces (triangles) from a .face file.        //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_face(char* filebasename)
	{
		FILE *infile;
		char infilename[FILENAMESIZE];
		char inputline[INPUTLINESIZE];
		char *stringptr;
		REAL attrib;
		int markers, corner;
		int index;
		int i, j;

		strcpy(infilename, filebasename);
		strcat(infilename, ".face");

		infile = fopen(infilename, "r");
		if (infile != (FILE *)NULL) {
			printf("Opening %s.\n", infilename);
		}
		else {
			return false;
		}

		// Read number of faces, boundary markers.
		stringptr = readnumberline(inputline, infile, infilename);
		numberoftrifaces = (int)strtol(stringptr, &stringptr, 0);
		stringptr = findnextnumber(stringptr);
		if (mesh_dim == 2) {
			// Skip a number.
			stringptr = findnextnumber(stringptr);
		}
		if (*stringptr == '\0') {
			markers = 0;  // Default there is no marker per face.
		}
		else {
			markers = (int)strtol(stringptr, &stringptr, 0);
		}
		if (numberoftrifaces > 0) {
			trifacelist = new int[numberoftrifaces * 3];
			if (trifacelist == (int *)NULL) {
				exit(1);
			}
			if (markers) {
				trifacemarkerlist = new int[numberoftrifaces];
				if (trifacemarkerlist == (int *)NULL) {
					exit(1);
				}
			}
		}

		// Read the list of faces.
		index = 0;
		for (i = 0; i < numberoftrifaces; i++) {
			// Read face index and the face's three corners.
			stringptr = readnumberline(inputline, infile, infilename);
			for (j = 0; j < 3; j++) {
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  Face %d is missing vertex %d in %s.\n",
						i + firstnumber, j + 1, infilename);
					exit(1);
				}
				corner = (int)strtol(stringptr, &stringptr, 0);
				if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
					printf("Error:  Face %d has an invalid vertex index.\n",
						i + firstnumber);
					exit(1);
				}
				trifacelist[index++] = corner;
			}
			if (numberofcorners == 10) {
				// Skip 3 extra vertices (generated by a previous -o2 option).
				for (j = 0; j < 3; j++) {
					stringptr = findnextnumber(stringptr);
				}
			}
			// Read the boundary marker if it exists.
			if (markers) {
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					attrib = 0.0;
				}
				else {
					attrib = (REAL)strtod(stringptr, &stringptr);
				}
				trifacemarkerlist[i] = (int)attrib;
			}
		}

		fclose(infile);

		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_tet()    Load a list of tetrahedra from a .ele file.                 //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_tet(char* filebasename)
	{
		FILE *infile;
		char infilename[FILENAMESIZE];
		char inputline[INPUTLINESIZE];
		char *stringptr;
		REAL attrib;
		int corner;
		int index, attribindex;
		int i, j;

		strcpy(infilename, filebasename);
		strcat(infilename, ".ele");

		infile = fopen(infilename, "r");
		if (infile != (FILE *)NULL) {
			printf("Opening %s.\n", infilename);
		}
		else {
			return false;
		}

		// Read number of elements, number of corners (4 or 10), number of
		//   element attributes.
		stringptr = readnumberline(inputline, infile, infilename);
		numberoftetrahedra = (int)strtol(stringptr, &stringptr, 0);
		if (numberoftetrahedra <= 0) {
			printf("Error:  Invalid number of tetrahedra.\n");
			fclose(infile);
			return false;
		}
		stringptr = findnextnumber(stringptr);
		if (*stringptr == '\0') {
			numberofcorners = 4;  // Default read 4 nodes per element.
		}
		else {
			numberofcorners = (int)strtol(stringptr, &stringptr, 0);
		}
		stringptr = findnextnumber(stringptr);
		if (*stringptr == '\0') {
			numberoftetrahedronattributes = 0; // Default no attribute.
		}
		else {
			numberoftetrahedronattributes = (int)strtol(stringptr, &stringptr, 0);
		}
		if (numberofcorners != 4 && numberofcorners != 10) {
			printf("Error:  Wrong number of corners %d (should be 4 or 10).\n",
				numberofcorners);
			fclose(infile);
			return false;
		}

		// Allocate memory for tetrahedra.
		tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
		if (tetrahedronlist == (int *)NULL) {
			exit(1);
		}
		// Allocate memory for output tetrahedron attributes if necessary.
		if (numberoftetrahedronattributes > 0) {
			tetrahedronattributelist = new REAL[numberoftetrahedra *
				numberoftetrahedronattributes];
			if (tetrahedronattributelist == (REAL *)NULL) {
				exit(1);
			}
		}

		// Read the list of tetrahedra.
		index = 0;
		attribindex = 0;
		for (i = 0; i < numberoftetrahedra; i++) {
			// Read tetrahedron index and the tetrahedron's corners.
			stringptr = readnumberline(inputline, infile, infilename);
			for (j = 0; j < numberofcorners; j++) {
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  Tetrahedron %d is missing vertex %d in %s.\n",
						i + firstnumber, j + 1, infilename);
					exit(1);
				}
				corner = (int)strtol(stringptr, &stringptr, 0);
				if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
					printf("Error:  Tetrahedron %d has an invalid vertex index.\n",
						i + firstnumber);
					exit(1);
				}
				tetrahedronlist[index++] = corner;
			}
			// Read the tetrahedron's attributes.
			for (j = 0; j < numberoftetrahedronattributes; j++) {
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					attrib = 0.0;
				}
				else {
					attrib = (REAL)strtod(stringptr, &stringptr);
				}
				tetrahedronattributelist[attribindex++] = attrib;
			}
		}

		fclose(infile);

		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_vol()    Load a list of volume constraints from a .vol file.         //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_vol(char* filebasename)
	{
		FILE *infile;
		char inelefilename[FILENAMESIZE];
		char infilename[FILENAMESIZE];
		char inputline[INPUTLINESIZE];
		char *stringptr;
		REAL volume;
		int volelements;
		int i;

		strcpy(infilename, filebasename);
		strcat(infilename, ".vol");

		infile = fopen(infilename, "r");
		if (infile != (FILE *)NULL) {
			printf("Opening %s.\n", infilename);
		}
		else {
			return false;
		}

		// Read number of tetrahedra.
		stringptr = readnumberline(inputline, infile, infilename);
		volelements = (int)strtol(stringptr, &stringptr, 0);
		if (volelements != numberoftetrahedra) {
			strcpy(inelefilename, filebasename);
			strcat(infilename, ".ele");
			printf("Warning:  %s and %s disagree on number of tetrahedra.\n",
				inelefilename, infilename);
			fclose(infile);
			return false;
		}

		tetrahedronvolumelist = new REAL[volelements];
		if (tetrahedronvolumelist == (REAL *)NULL) {
			exit(1);
		}

		// Read the list of volume constraints.
		for (i = 0; i < volelements; i++) {
			stringptr = readnumberline(inputline, infile, infilename);
			stringptr = findnextnumber(stringptr);
			if (*stringptr == '\0') {
				volume = -1.0; // No constraint on this tetrahedron.
			}
			else {
				volume = (REAL)strtod(stringptr, &stringptr);
			}
			tetrahedronvolumelist[i] = volume;
		}

		fclose(infile);

		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_var()    Load constraints applied on facets, segments, and nodes     //
	//               from a .var file.                                           //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_var(char* filebasename)
	{
		FILE *infile;
		char varfilename[FILENAMESIZE];
		char inputline[INPUTLINESIZE];
		char *stringptr;
		int index;
		int i;

		// Variant constraints are saved in file "filename.var".
		strcpy(varfilename, filebasename);
		strcat(varfilename, ".var");
		infile = fopen(varfilename, "r");
		if (infile != (FILE *)NULL) {
			printf("Opening %s.\n", varfilename);
		}
		else {
			return false;
		}

		// Read the facet constraint section.
		stringptr = readnumberline(inputline, infile, varfilename);
		if (*stringptr != '\0') {
			numberoffacetconstraints = (int)strtol(stringptr, &stringptr, 0);
		}
		else {
			numberoffacetconstraints = 0;
		}
		if (numberoffacetconstraints > 0) {
			// Initialize 'facetconstraintlist'.
			facetconstraintlist = new REAL[numberoffacetconstraints * 2];
			index = 0;
			for (i = 0; i < numberoffacetconstraints; i++) {
				stringptr = readnumberline(inputline, infile, varfilename);
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  facet constraint %d has no facet marker.\n",
						firstnumber + i);
					break;
				}
				else {
					facetconstraintlist[index++] = (REAL)strtod(stringptr, &stringptr);
				}
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  facet constraint %d has no maximum area bound.\n",
						firstnumber + i);
					break;
				}
				else {
					facetconstraintlist[index++] = (REAL)strtod(stringptr, &stringptr);
				}
			}
			if (i < numberoffacetconstraints) {
				// This must be caused by an error.
				fclose(infile);
				return false;
			}
		}

		// Read the segment constraint section.
		stringptr = readnumberline(inputline, infile, varfilename);
		if (*stringptr != '\0') {
			numberofsegmentconstraints = (int)strtol(stringptr, &stringptr, 0);
		}
		else {
			numberofsegmentconstraints = 0;
		}
		if (numberofsegmentconstraints > 0) {
			// Initialize 'segmentconstraintlist'.
			segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
			index = 0;
			for (i = 0; i < numberofsegmentconstraints; i++) {
				stringptr = readnumberline(inputline, infile, varfilename);
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  segment constraint %d has no frist endpoint.\n",
						firstnumber + i);
					break;
				}
				else {
					segmentconstraintlist[index++] = (REAL)strtod(stringptr, &stringptr);
				}
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  segment constraint %d has no second endpoint.\n",
						firstnumber + i);
					break;
				}
				else {
					segmentconstraintlist[index++] = (REAL)strtod(stringptr, &stringptr);
				}
				stringptr = findnextnumber(stringptr);
				if (*stringptr == '\0') {
					printf("Error:  segment constraint %d has no maximum length bound.\n",
						firstnumber + i);
					break;
				}
				else {
					segmentconstraintlist[index++] = (REAL)strtod(stringptr, &stringptr);
				}
			}
			if (i < numberofsegmentconstraints) {
				// This must be caused by an error.
				fclose(infile);
				return false;
			}
		}

		fclose(infile);
		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_mtr()    Load a size specification map from a .mtr file.             //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_mtr(char* filebasename)
	{
		FILE *infile;
		char mtrfilename[FILENAMESIZE];
		char inputline[INPUTLINESIZE];
		char *stringptr;
		REAL mtr;
		int ptnum;
		int mtrindex;
		int i, j;

		strcpy(mtrfilename, filebasename);
		strcat(mtrfilename, ".mtr");
		infile = fopen(mtrfilename, "r");
		if (infile != (FILE *)NULL) {
			printf("Opening %s.\n", mtrfilename);
		}
		else {
			return false;
		}

		// Read the number of points.
		stringptr = readnumberline(inputline, infile, mtrfilename);
		ptnum = (int)strtol(stringptr, &stringptr, 0);
		if (ptnum != numberofpoints) {
			printf("  !! Point numbers are not equal. Ignored.\n");
			fclose(infile);
			return false;
		}
		// Read the number of columns (1, 3, or 6).
		stringptr = findnextnumber(stringptr); // Skip number of points.
		if (*stringptr != '\0') {
			numberofpointmtrs = (int)strtol(stringptr, &stringptr, 0);
		}
		if (numberofpointmtrs == 0) {
			// Column number doesn't match. Set a default number (1).
			numberofpointmtrs = 1;
		}

		// Allocate space for pointmtrlist.
		pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
		if (pointmtrlist == (REAL *)NULL) {
			exit(1);
		}
		mtrindex = 0;
		for (i = 0; i < numberofpoints; i++) {
			// Read metrics.
			stringptr = readnumberline(inputline, infile, mtrfilename);
			for (j = 0; j < numberofpointmtrs; j++) {
				if (*stringptr == '\0') {
					printf("Error:  Metric %d is missing value #%d in %s.\n",
						i + firstnumber, j + 1, mtrfilename);
					exit(1);
				}
				mtr = (REAL)strtod(stringptr, &stringptr);
				pointmtrlist[mtrindex++] = mtr;
				stringptr = findnextnumber(stringptr);
			}
		}

		fclose(infile);
		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_poly()    Load a PL complex from a .poly or a .smesh file.           //
	//      读入.poly文件                                                                  //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_poly(const string& fname)
	{
		FILE *infile;	//网格文件

		char inpolyfilename[FILENAMESIZE];		//.poly文件的名称
		char insmeshfilename[FILENAMESIZE];		//.smesh文件的名称

		char inputline[INPUTLINESIZE];
		char *stringptr, *infilename;
		int smesh, markers, uvflag, currentmarker;

		int index;
		int i, j, k;

		// Assembling the actual file names we want to open.
		strcpy(inpolyfilename, fname.c_str());
		strcpy(insmeshfilename, fname.c_str());
		strcat(inpolyfilename, ".poly");
		strcat(insmeshfilename, ".smesh");

		// First assume it is a .poly file.
		smesh = 0;
		// Try to open a .poly file.
		infile = fopen(inpolyfilename, "r");

		if (infile == (FILE *)NULL) 
		{
			// .poly doesn't exist! Try to open a .smesh file.
			infile = fopen(insmeshfilename, "r");

			if (infile == (FILE *)NULL) 
			{
				printf("  Cannot access file %s and %s.\n",inpolyfilename, insmeshfilename);
				return false;
			}
			else 
			{
				printf("Opening %s.\n", insmeshfilename);
				infilename = insmeshfilename;
			}
			smesh = 1;
		}
		else 
		{
			printf("Opening %s.\n", inpolyfilename);
			infilename = inpolyfilename;
		}

		// Initialize the default values.
		markers = 0;  // no boundary marker.
		uvflag = 0; // no uv parameters (required by a PSC).

		// Read number of points, number of dimensions, number of point
		//   attributes, and number of boundary markers.
		//读入节点数目，维度，节点属性，节点的part号
		stringptr = readnumberline(inputline, infile, infilename);
		numberofpoints = (int)strtol(stringptr, &stringptr, 0);
		stringptr = findnextnumber(stringptr);

		if (*stringptr != '\0') 
		{
			mesh_dim = (int)strtol(stringptr, &stringptr, 0);
		}
		stringptr = findnextnumber(stringptr);
		if (*stringptr != '\0') 
		{
			numberofpointattributes = (int)strtol(stringptr, &stringptr, 0);
		}
		stringptr = findnextnumber(stringptr);
		if (*stringptr != '\0') 
		{
			markers = (int)strtol(stringptr, &stringptr, 0);
		}
		if (*stringptr != '\0') 
		{
			uvflag = (int)strtol(stringptr, &stringptr, 0);
		}

		if (numberofpoints > 0) 
		{
			// Load the list of nodes.
			if (!load_node_call(infile, markers, uvflag, infilename)) 
			{
				fclose(infile);
				return false;
			}
		}
		else 
		{
			// If the .poly or .smesh file claims there are zero points, that
			//   means the points should be read from a separate .node file.
			if (!load_node(fname.c_str())) 
			{
				fclose(infile);
				return false;
			}
		}

		if ((mesh_dim != 3) && (mesh_dim != 2))
		{
			printf("Input error:  TetGen only works for 2D & 3D point sets.\n");
			fclose(infile);
			return false;
		}

		if (numberofpoints < (mesh_dim + 1))
		{
			printf("Input error:  TetGen needs at least %d points.\n", mesh_dim + 1);
			fclose(infile);
			return false;
		}

		facet *f;
		polygon *p;

		if (mesh_dim == 3)
		{
			// Read number of facets and number of boundary markers.
			stringptr = readnumberline(inputline, infile, infilename);
			if (stringptr == NULL) 
			{
				// No facet list, return.
				fclose(infile);
				return true;
			}
			numberoffacets = (int)strtol(stringptr, &stringptr, 0);
			if (numberoffacets <= 0) {
				// No facet list, return.
				fclose(infile);
				return true;
			}
			stringptr = findnextnumber(stringptr);
			if (*stringptr == '\0') {
				markers = 0;  // no boundary marker.
			}
			else {
				markers = (int)strtol(stringptr, &stringptr, 0);
			}

			// Initialize the 'facetlist', 'facetmarkerlist'.
			facetlist = new facet[numberoffacets];
			if (markers == 1) {
				facetmarkerlist = new int[numberoffacets];
			}

			// Read data into 'facetlist', 'facetmarkerlist'.
			if (smesh == 0) {
				// Facets are in .poly file format.
				for (i = 1; i <= numberoffacets; i++) {
					f = &(facetlist[i - 1]);
					init(f);
					f->numberofholes = 0;
					currentmarker = 0;
					// Read number of polygons, number of holes, and a boundary marker.
					stringptr = readnumberline(inputline, infile, infilename);
					f->numberofpolygons = (int)strtol(stringptr, &stringptr, 0);
					stringptr = findnextnumber(stringptr);
					if (*stringptr != '\0') {
						f->numberofholes = (int)strtol(stringptr, &stringptr, 0);
						if (markers == 1) {
							stringptr = findnextnumber(stringptr);
							if (*stringptr != '\0') {
								currentmarker = (int)strtol(stringptr, &stringptr, 0);
							}
						}
					}
					// Initialize facetmarker if it needs.
					if (markers == 1) {
						facetmarkerlist[i - 1] = currentmarker;
					}
					// Each facet should has at least one polygon.
					if (f->numberofpolygons <= 0) {
						printf("Error:  Wrong number of polygon in %d facet.\n", i);
						break;
					}
					// Initialize the 'f->polygonlist'.
					f->polygonlist = new polygon[f->numberofpolygons];
					// Go through all polygons, read in their vertices.
					for (j = 1; j <= f->numberofpolygons; j++) {
						p = &(f->polygonlist[j - 1]);
						init(p);
						// Read number of vertices of this polygon.
						stringptr = readnumberline(inputline, infile, infilename);
						p->numberofvertices = (int)strtol(stringptr, &stringptr, 0);
						if (p->numberofvertices < 1) {
							printf("Error:  Wrong polygon %d in facet %d\n", j, i);
							break;
						}
						// Initialize 'p->vertexlist'.
						p->vertexlist = new int[p->numberofvertices];
						// Read all vertices of this polygon.
						for (k = 1; k <= p->numberofvertices; k++) {
							stringptr = findnextnumber(stringptr);
							if (*stringptr == '\0') {
								// Try to load another non-empty line and continue to read the
								//   rest of vertices.
								stringptr = readnumberline(inputline, infile, infilename);
								if (*stringptr == '\0') {
									printf("Error: Missing %d endpoints of polygon %d in facet %d",
										p->numberofvertices - k, j, i);
									break;
								}
							}
							p->vertexlist[k - 1] = (int)strtol(stringptr, &stringptr, 0);
						}
					}
					if (j <= f->numberofpolygons) {
						// This must be caused by an error. However, there're j - 1
						//   polygons have been read. Reset the 'f->numberofpolygon'.
						if (j == 1) {
							// This is the first polygon.
							delete[] f->polygonlist;
						}
						f->numberofpolygons = j - 1;
						// No hole will be read even it exists.
						f->numberofholes = 0;
						break;
					}
					// If this facet has hole pints defined, read them.
					if (f->numberofholes > 0) {
						// Initialize 'f->holelist'.
						f->holelist = new REAL[f->numberofholes * 3];
						// Read the holes' coordinates.
						index = 0;
						for (j = 1; j <= f->numberofholes; j++) {
							stringptr = readnumberline(inputline, infile, infilename);
							for (k = 1; k <= 3; k++) {
								stringptr = findnextnumber(stringptr);
								if (*stringptr == '\0') {
									printf("Error:  Hole %d in facet %d has no coordinates", j, i);
									break;
								}
								f->holelist[index++] = (REAL)strtod(stringptr, &stringptr);
							}
							if (k <= 3) {
								// This must be caused by an error.
								break;
							}
						}
						if (j <= f->numberofholes) {
							// This must be caused by an error.
							break;
						}
					}
				}
				if (i <= numberoffacets) {
					// This must be caused by an error.
					numberoffacets = i - 1;
					fclose(infile);
					return false;
				}
			}
			else { // poly == 0
				// Read the facets from a .smesh file.
				for (i = 1; i <= numberoffacets; i++) {
					f = &(facetlist[i - 1]);
					init(f);
					// Initialize 'f->facetlist'. In a .smesh file, each facetlist only
					//   contains exactly one polygon, no hole.
					f->numberofpolygons = 1;
					f->polygonlist = new polygon[f->numberofpolygons];
					p = &(f->polygonlist[0]);
					init(p);
					// Read number of vertices of this polygon.
					stringptr = readnumberline(inputline, infile, insmeshfilename);
					p->numberofvertices = (int)strtol(stringptr, &stringptr, 0);
					if (p->numberofvertices < 1) {
						printf("Error:  Wrong number of vertex in facet %d\n", i);
						break;
					}
					// Initialize 'p->vertexlist'.
					p->vertexlist = new int[p->numberofvertices];
					for (k = 1; k <= p->numberofvertices; k++) {
						stringptr = findnextnumber(stringptr);
						if (*stringptr == '\0') {
							// Try to load another non-empty line and continue to read the
							//   rest of vertices.
							stringptr = readnumberline(inputline, infile, infilename);
							if (*stringptr == '\0') {
								printf("Error:  Missing %d endpoints in facet %d",
									p->numberofvertices - k, i);
								break;
							}
						}
						p->vertexlist[k - 1] = (int)strtol(stringptr, &stringptr, 0);
					}
					if (k <= p->numberofvertices) {
						// This must be caused by an error.
						break;
					}
					// Read facet's boundary marker at last.
					if (markers == 1) {
						stringptr = findnextnumber(stringptr);
						if (*stringptr == '\0') {
							currentmarker = 0;
						}
						else {
							currentmarker = (int)strtol(stringptr, &stringptr, 0);
						}
						facetmarkerlist[i - 1] = currentmarker;
					}
				}
				if (i <= numberoffacets) {
					// This must be caused by an error.
					numberoffacets = i - 1;
					fclose(infile);
					return false;
				}
			}

			// Read the hole section.
			stringptr = readnumberline(inputline, infile, infilename);
			if (stringptr == NULL) {
				// No hole list, return.
				fclose(infile);
				return true;
			}
			if (*stringptr != '\0') {
				numberofholes = (int)strtol(stringptr, &stringptr, 0);
			}
			else {
				numberofholes = 0;
			}
			if (numberofholes > 0) {
				// Initialize 'holelist'.
				holelist = new REAL[numberofholes * 3];
				for (i = 0; i < 3 * numberofholes; i += 3) {
					stringptr = readnumberline(inputline, infile, infilename);
					stringptr = findnextnumber(stringptr);
					if (*stringptr == '\0') {
						printf("Error:  Hole %d has no x coord.\n", firstnumber + (i / 3));
						break;
					}
					else {
						holelist[i] = (REAL)strtod(stringptr, &stringptr);
					}
					stringptr = findnextnumber(stringptr);
					if (*stringptr == '\0') {
						printf("Error:  Hole %d has no y coord.\n", firstnumber + (i / 3));
						break;
					}
					else {
						holelist[i + 1] = (REAL)strtod(stringptr, &stringptr);
					}
					stringptr = findnextnumber(stringptr);
					if (*stringptr == '\0') {
						printf("Error:  Hole %d has no z coord.\n", firstnumber + (i / 3));
						break;
					}
					else {
						holelist[i + 2] = (REAL)strtod(stringptr, &stringptr);
					}
				}
				if (i < 3 * numberofholes) {
					// This must be caused by an error.
					fclose(infile);
					return false;
				}
			}

			// Read the region section.  The 'region' section is optional, if we
			//   don't reach the end-of-file, try read it in.
			stringptr = readnumberline(inputline, infile, NULL);
			if (stringptr != (char *)NULL && *stringptr != '\0') {
				numberofregions = (int)strtol(stringptr, &stringptr, 0);
			}
			else {
				numberofregions = 0;
			}
			if (numberofregions > 0) {
				// Initialize 'regionlist'.
				regionlist = new REAL[numberofregions * 5];
				index = 0;
				for (i = 0; i < numberofregions; i++) {
					stringptr = readnumberline(inputline, infile, infilename);
					stringptr = findnextnumber(stringptr);
					if (*stringptr == '\0') {
						printf("Error:  Region %d has no x coordinate.\n", firstnumber + i);
						break;
					}
					else {
						regionlist[index++] = (REAL)strtod(stringptr, &stringptr);
					}
					stringptr = findnextnumber(stringptr);
					if (*stringptr == '\0') {
						printf("Error:  Region %d has no y coordinate.\n", firstnumber + i);
						break;
					}
					else {
						regionlist[index++] = (REAL)strtod(stringptr, &stringptr);
					}
					stringptr = findnextnumber(stringptr);
					if (*stringptr == '\0') {
						printf("Error:  Region %d has no z coordinate.\n", firstnumber + i);
						break;
					}
					else {
						regionlist[index++] = (REAL)strtod(stringptr, &stringptr);
					}
					stringptr = findnextnumber(stringptr);
					if (*stringptr == '\0') {
						printf("Error:  Region %d has no region attrib.\n", firstnumber + i);
						break;
					}
					else {
						regionlist[index++] = (REAL)strtod(stringptr, &stringptr);
					}
					stringptr = findnextnumber(stringptr);
					if (*stringptr == '\0') {
						regionlist[index] = regionlist[index - 1];
					}
					else {
						regionlist[index] = (REAL)strtod(stringptr, &stringptr);
					}
					index++;
				}
				if (i < numberofregions) {
					// This must be caused by an error.
					fclose(infile);
					return false;
				}
			}

		}
		else
		{
			// Read a PSLG from Triangle's poly file.
			assert(mesh_dim == 2);
			// A PSLG is a facet of a PLC.
			numberoffacets = 1;
			// Initialize the 'facetlist'.
			facetlist = new facet[numberoffacets];
			facetmarkerlist = (int *)NULL; // No facet markers.
			f = &(facetlist[0]);
			init(f);
			// Read number of segments.
			stringptr = readnumberline(inputline, infile, infilename);
			// Segments are degenerate polygons.
			f->numberofpolygons = (int)strtol(stringptr, &stringptr, 0);
			if (f->numberofpolygons > 0) {
				f->polygonlist = new polygon[f->numberofpolygons];
			}
			// Go through all segments, read in their vertices.
			for (j = 0; j < f->numberofpolygons; j++) {
				p = &(f->polygonlist[j]);
				init(p);
				// Read in a segment.
				stringptr = readnumberline(inputline, infile, infilename);
				stringptr = findnextnumber(stringptr); // Skip its index.
				p->numberofvertices = 2; // A segment always has two vertices.
				p->vertexlist = new int[p->numberofvertices];
				p->vertexlist[0] = (int)strtol(stringptr, &stringptr, 0);
				stringptr = findnextnumber(stringptr);
				p->vertexlist[1] = (int)strtol(stringptr, &stringptr, 0);
			}
			// Read number of holes.
			stringptr = readnumberline(inputline, infile, infilename);
			f->numberofholes = (int)strtol(stringptr, &stringptr, 0);
			if (f->numberofholes > 0) {
				// Initialize 'f->holelist'.
				f->holelist = new REAL[f->numberofholes * 3];
				// Read the holes' coordinates.
				for (j = 0; j < f->numberofholes; j++) {
					// Read a 2D hole point.
					stringptr = readnumberline(inputline, infile, infilename);
					stringptr = findnextnumber(stringptr); // Skip its index.
					f->holelist[j * 3] = (REAL)strtod(stringptr, &stringptr);
					stringptr = findnextnumber(stringptr);
					f->holelist[j * 3 + 1] = (REAL)strtod(stringptr, &stringptr);
					f->holelist[j * 3 + 2] = 0.0; // The z-coord.
				}
			}
			// The regions are skipped.

		}

		// End of reading poly/smesh file.
		fclose(infile);
		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_off()    Load a polyhedron from a .off file.                         //
	//                                                                           //
	// The .off format is one of file formats of the Geomview, an interactive    //
	// program for viewing and manipulating geometric objects.  More information //
	// is available form: http://www.geomview.org.                               //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_off(char* filebasename)
	{
		FILE *fp;
		tetgenio::facet *f;
		tetgenio::polygon *p;
		char infilename[FILENAMESIZE];
		char buffer[INPUTLINESIZE];
		char *bufferp;
		double *coord;
		int nverts = 0, iverts = 0;
		int nfaces = 0, ifaces = 0;
		int nedges = 0;
		int line_count = 0, i;

		// Default, the off file's index is from '0'. We check it by remembering the
		//   smallest index we found in the file. It should be either 0 or 1.
		int smallestidx = 0;

		strncpy(infilename, filebasename, 1024 - 1);
		infilename[FILENAMESIZE - 1] = '\0';
		if (infilename[0] == '\0') {
			printf("Error:  No filename.\n");
			return false;
		}
		if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
			strcat(infilename, ".off");
		}

		if (!(fp = fopen(infilename, "r"))) {
			printf("  Unable to open file %s\n", infilename);
			return false;
		}
		printf("Opening %s.\n", infilename);

		while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
			// Check section
			if (nverts == 0) {
				// Read header 
				bufferp = strstr(bufferp, "OFF");
				if (bufferp != NULL) {
					// Read mesh counts
					bufferp = findnextnumber(bufferp); // Skip field "OFF".
					if (*bufferp == '\0') {
						// Read a non-empty line.
						bufferp = readline(buffer, fp, &line_count);
					}
					if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3)
						|| (nverts == 0)) {
						printf("Syntax error reading header on line %d in file %s\n",
							line_count, infilename);
						fclose(fp);
						return false;
					}
					// Allocate memory for 'tetgenio'
					if (nverts > 0) {
						numberofpoints = nverts;
						pointlist = new REAL[nverts * 3];
						smallestidx = nverts + 1; // A bigger enough number.
					}
					if (nfaces > 0) {
						numberoffacets = nfaces;
						facetlist = new tetgenio::facet[nfaces];
					}
				}
			}
			else if (iverts < nverts) {
				// Read vertex coordinates
				coord = &pointlist[iverts * 3];
				for (i = 0; i < 3; i++) {
					if (*bufferp == '\0') {
						printf("Syntax error reading vertex coords on line %d in file %s\n",
							line_count, infilename);
						fclose(fp);
						return false;
					}
					coord[i] = (REAL)strtod(bufferp, &bufferp);
					bufferp = findnextnumber(bufferp);
				}
				iverts++;
			}
			else if (ifaces < nfaces) {
				// Get next face
				f = &facetlist[ifaces];
				init(f);
				// In .off format, each facet has one polygon, no hole.
				f->numberofpolygons = 1;
				f->polygonlist = new tetgenio::polygon[1];
				p = &f->polygonlist[0];
				init(p);
				// Read the number of vertices, it should be greater than 0.
				p->numberofvertices = (int)strtol(bufferp, &bufferp, 0);
				if (p->numberofvertices == 0) {
					printf("Syntax error reading polygon on line %d in file %s\n",
						line_count, infilename);
					fclose(fp);
					return false;
				}
				// Allocate memory for face vertices
				p->vertexlist = new int[p->numberofvertices];
				for (i = 0; i < p->numberofvertices; i++) {
					bufferp = findnextnumber(bufferp);
					if (*bufferp == '\0') {
						printf("Syntax error reading polygon on line %d in file %s\n",
							line_count, infilename);
						fclose(fp);
						return false;
					}
					p->vertexlist[i] = (int)strtol(bufferp, &bufferp, 0);
					// Detect the smallest index.
					if (p->vertexlist[i] < smallestidx) {
						smallestidx = p->vertexlist[i];
					}
				}
				ifaces++;
			}
			else {
				// Should never get here
				printf("Found extra text starting at line %d in file %s\n", line_count,
					infilename);
				break;
			}
		}

		// Close file
		fclose(fp);

		// Decide the firstnumber of the index.
		if (smallestidx == 0) {
			firstnumber = 0;
		}
		else if (smallestidx == 1) {
			firstnumber = 1;
		}
		else {
			printf("A wrong smallest index (%d) was detected in file %s\n",
				smallestidx, infilename);
			return false;
		}

		if (iverts != nverts) {
			printf("Expected %d vertices, but read only %d vertices in file %s\n",
				nverts, iverts, infilename);
			return false;
		}
		if (ifaces != nfaces) {
			printf("Expected %d faces, but read only %d faces in file %s\n",
				nfaces, ifaces, infilename);
			return false;
		}

		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_ply()    Load a polyhedron from a .ply file.                         //
	//                                                                           //
	// This is a simplified version of reading .ply files, which only reads the  //
	// set of vertices and the set of faces. Other informations (such as color,  //
	// material, texture, etc) in .ply file are ignored. Complete routines for   //
	// reading and writing ,ply files are available from: http://www.cc.gatech.  //
	// edu/projects/large_models/ply.html.  Except the header section, ply file  //
	// format has exactly the same format for listing vertices and polygons as   //
	// off file format.                                                          //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_ply(char* filebasename)
	{
		FILE *fp;
		tetgenio::facet *f;
		tetgenio::polygon *p;
		char infilename[FILENAMESIZE];
		char buffer[INPUTLINESIZE];
		char *bufferp, *str;
		double *coord;
		int endheader = 0, format = 0;
		int nverts = 0, iverts = 0;
		int nfaces = 0, ifaces = 0;
		int line_count = 0, i;

		// Default, the ply file's index is from '0'. We check it by remembering the
		//   smallest index we found in the file. It should be either 0 or 1.
		int smallestidx = 0;

		strncpy(infilename, filebasename, FILENAMESIZE - 1);
		infilename[FILENAMESIZE - 1] = '\0';
		if (infilename[0] == '\0') {
			printf("Error:  No filename.\n");
			return false;
		}
		if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
			strcat(infilename, ".ply");
		}

		if (!(fp = fopen(infilename, "r"))) {
			printf("Error:  Unable to open file %s\n", infilename);
			return false;
		}
		printf("Opening %s.\n", infilename);

		while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
			if (!endheader) {
				// Find if it is the keyword "end_header".
				str = strstr(bufferp, "end_header");
				// strstr() is case sensitive.
				if (!str) str = strstr(bufferp, "End_header");
				if (!str) str = strstr(bufferp, "End_Header");
				if (str) {
					// This is the end of the header section.
					endheader = 1;
					continue;
				}
				// Parse the number of vertices and the number of faces.
				if (nverts == 0 || nfaces == 0) {
					// Find if it si the keyword "element".
					str = strstr(bufferp, "element");
					if (!str) str = strstr(bufferp, "Element");
					if (str) {
						bufferp = findnextfield(str);
						if (*bufferp == '\0') {
							printf("Syntax error reading element type on line%d in file %s\n",
								line_count, infilename);
							fclose(fp);
							return false;
						}
						if (nverts == 0) {
							// Find if it is the keyword "vertex".
							str = strstr(bufferp, "vertex");
							if (!str) str = strstr(bufferp, "Vertex");
							if (str) {
								bufferp = findnextnumber(str);
								if (*bufferp == '\0') {
									printf("Syntax error reading vertex number on line");
									printf(" %d in file %s\n", line_count, infilename);
									fclose(fp);
									return false;
								}
								nverts = (int)strtol(bufferp, &bufferp, 0);
								// Allocate memory for 'tetgenio'
								if (nverts > 0) {
									numberofpoints = nverts;
									pointlist = new REAL[nverts * 3];
									smallestidx = nverts + 1; // A big enough index.
								}
							}
						}
						if (nfaces == 0) {
							// Find if it is the keyword "face".
							str = strstr(bufferp, "face");
							if (!str) str = strstr(bufferp, "Face");
							if (str) {
								bufferp = findnextnumber(str);
								if (*bufferp == '\0') {
									printf("Syntax error reading face number on line");
									printf(" %d in file %s\n", line_count, infilename);
									fclose(fp);
									return false;
								}
								nfaces = (int)strtol(bufferp, &bufferp, 0);
								// Allocate memory for 'tetgenio'
								if (nfaces > 0) {
									numberoffacets = nfaces;
									facetlist = new tetgenio::facet[nfaces];
								}
							}
						}
					} // It is not the string "element". 
				}
				if (format == 0) {
					// Find the keyword "format".
					str = strstr(bufferp, "format");
					if (!str) str = strstr(bufferp, "Format");
					if (str) {
						format = 1;
						bufferp = findnextfield(str);
						// Find if it is the string "ascii".
						str = strstr(bufferp, "ascii");
						if (!str) str = strstr(bufferp, "ASCII");
						if (!str) {
							printf("This routine only reads ascii format of ply files.\n");
							printf("Hint: You can convert the binary to ascii format by\n");
							printf("  using the provided ply tools:\n");
							printf("  ply2ascii < %s > ascii_%s\n", infilename, infilename);
							fclose(fp);
							return false;
						}
					}
				}
			}
			else if (iverts < nverts) {
				// Read vertex coordinates
				coord = &pointlist[iverts * 3];
				for (i = 0; i < 3; i++) {
					if (*bufferp == '\0') {
						printf("Syntax error reading vertex coords on line %d in file %s\n",
							line_count, infilename);
						fclose(fp);
						return false;
					}
					coord[i] = (REAL)strtod(bufferp, &bufferp);
					bufferp = findnextnumber(bufferp);
				}
				iverts++;
			}
			else if (ifaces < nfaces) {
				// Get next face
				f = &facetlist[ifaces];
				init(f);
				// In .off format, each facet has one polygon, no hole.
				f->numberofpolygons = 1;
				f->polygonlist = new tetgenio::polygon[1];
				p = &f->polygonlist[0];
				init(p);
				// Read the number of vertices, it should be greater than 0.
				p->numberofvertices = (int)strtol(bufferp, &bufferp, 0);
				if (p->numberofvertices == 0) {
					printf("Syntax error reading polygon on line %d in file %s\n",
						line_count, infilename);
					fclose(fp);
					return false;
				}
				// Allocate memory for face vertices
				p->vertexlist = new int[p->numberofvertices];
				for (i = 0; i < p->numberofvertices; i++) {
					bufferp = findnextnumber(bufferp);
					if (*bufferp == '\0') {
						printf("Syntax error reading polygon on line %d in file %s\n",
							line_count, infilename);
						fclose(fp);
						return false;
					}
					p->vertexlist[i] = (int)strtol(bufferp, &bufferp, 0);
					if (p->vertexlist[i] < smallestidx) {
						smallestidx = p->vertexlist[i];
					}
				}
				ifaces++;
			}
			else {
				// Should never get here
				printf("Found extra text starting at line %d in file %s\n", line_count,
					infilename);
				break;
			}
		}

		// Close file
		fclose(fp);

		// Decide the firstnumber of the index.
		if (smallestidx == 0) {
			firstnumber = 0;
		}
		else if (smallestidx == 1) {
			firstnumber = 1;
		}
		else {
			printf("A wrong smallest index (%d) was detected in file %s\n",
				smallestidx, infilename);
			return false;
		}

		if (iverts != nverts) {
			printf("Expected %d vertices, but read only %d vertices in file %s\n",
				nverts, iverts, infilename);
			return false;
		}
		if (ifaces != nfaces) {
			printf("Expected %d faces, but read only %d faces in file %s\n",
				nfaces, ifaces, infilename);
			return false;
		}

		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_stl()    Load a surface mesh from a .stl file.                       //
	//                                                                           //
	// The .stl or stereolithography format is an ASCII or binary file used in   //
	// manufacturing.  It is a list of the triangular surfaces that describe a   //
	// computer generated solid model. This is the standard input for most rapid //
	// prototyping machines.                                                     //
	//                                                                           //
	// Comment: A .stl file many contain many duplicated points.  They will be   //
	// unified during the Delaunay tetrahedralization process.                   //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_stl(char* filebasename)
	{
		FILE *fp;
		tetgenmesh::arraypool *plist;
		tetgenio::facet *f;
		tetgenio::polygon *p;
		char infilename[FILENAMESIZE];
		char buffer[INPUTLINESIZE];
		char *bufferp, *str;
		double *coord;
		int solid = 0;
		int nverts = 0, iverts = 0;
		int nfaces = 0;
		int line_count = 0, i;

		strncpy(infilename, filebasename, FILENAMESIZE - 1);
		infilename[FILENAMESIZE - 1] = '\0';
		if (infilename[0] == '\0') {
			printf("Error:  No filename.\n");
			return false;
		}
		if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
			strcat(infilename, ".stl");
		}

		if (!(fp = fopen(infilename, "r"))) {
			printf("Error:  Unable to open file %s\n", infilename);
			return false;
		}
		printf("Opening %s.\n", infilename);

		// STL file has no number of points available. Use a list to read points.
		plist = new tetgenmesh::arraypool(sizeof(double)* 3, 10);

		while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
			// The ASCII .stl file must start with the lower case keyword solid and
			//   end with endsolid.
			if (solid == 0) {
				// Read header 
				bufferp = strstr(bufferp, "solid");
				if (bufferp != NULL) {
					solid = 1;
				}
			}
			else {
				// We're inside the block of the solid.
				str = bufferp;
				// Is this the end of the solid.
				bufferp = strstr(bufferp, "endsolid");
				if (bufferp != NULL) {
					solid = 0;
				}
				else {
					// Read the XYZ coordinates if it is a vertex.
					bufferp = str;
					bufferp = strstr(bufferp, "vertex");
					if (bufferp != NULL) {
						plist->newindex((void **)&coord);
						for (i = 0; i < 3; i++) {
							bufferp = findnextnumber(bufferp);
							if (*bufferp == '\0') {
								printf("Syntax error reading vertex coords on line %d\n",
									line_count);
								delete plist;
								fclose(fp);
								return false;
							}
							coord[i] = (REAL)strtod(bufferp, &bufferp);
						}
					}
				}
			}
		}
		fclose(fp);

		nverts = (int)plist->objects;
		// nverts should be an integer times 3 (every 3 vertices denote a face).
		if (nverts == 0 || (nverts % 3 != 0)) {
			printf("Error:  Wrong number of vertices in file %s.\n", infilename);
			delete plist;
			return false;
		}
		numberofpoints = nverts;
		pointlist = new REAL[nverts * 3];
		for (i = 0; i < nverts; i++) {
			coord = (double *)fastlookup(plist, i);
			iverts = i * 3;
			pointlist[iverts] = (REAL)coord[0];
			pointlist[iverts + 1] = (REAL)coord[1];
			pointlist[iverts + 2] = (REAL)coord[2];
		}

		nfaces = (int)(nverts / 3);
		numberoffacets = nfaces;
		facetlist = new tetgenio::facet[nfaces];

		// Default use '1' as the array starting index.
		firstnumber = 1;
		iverts = firstnumber;
		for (i = 0; i < nfaces; i++) {
			f = &facetlist[i];
			init(f);
			// In .stl format, each facet has one polygon, no hole.
			f->numberofpolygons = 1;
			f->polygonlist = new tetgenio::polygon[1];
			p = &f->polygonlist[0];
			init(p);
			// Each polygon has three vertices.
			p->numberofvertices = 3;
			p->vertexlist = new int[p->numberofvertices];
			p->vertexlist[0] = iverts;
			p->vertexlist[1] = iverts + 1;
			p->vertexlist[2] = iverts + 2;
			iverts += 3;
		}

		delete plist;
		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_medit()    Load a surface mesh from a .mesh file.                    //
	//                                                                           //
	// The .mesh format is the file format of Medit, a user-friendly interactive //
	// mesh viewer program.                                                      //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_medit(char* filebasename, int istetmesh)
	{
		FILE *fp;
		tetgenio::facet *tmpflist, *f;
		tetgenio::polygon *p;
		char infilename[FILENAMESIZE];
		char buffer[INPUTLINESIZE];
		char *bufferp, *str;
		double *coord;
		int *tmpfmlist;
		int dimension = 0;
		int nverts = 0;
		int nfaces = 0;
		int ntets = 0;
		int line_count = 0;
		int corners = 0; // 3 (triangle) or 4 (quad).
		int *plist;
		int i, j;

		int smallestidx = 0;

		strncpy(infilename, filebasename, FILENAMESIZE - 1);
		infilename[FILENAMESIZE - 1] = '\0';
		if (infilename[0] == '\0') {
			printf("Error:  No filename.\n");
			return false;
		}
		if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
			strcat(infilename, ".mesh");
		}

		if (!(fp = fopen(infilename, "r"))) {
			printf("Error:  Unable to open file %s\n", infilename);
			return false;
		}
		printf("Opening %s.\n", infilename);

		while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
			if (*bufferp == '#') continue;  // A comment line is skipped.
			if (dimension == 0) {
				// Find if it is the keyword "Dimension".
				str = strstr(bufferp, "Dimension");
				if (!str) str = strstr(bufferp, "dimension");
				if (!str) str = strstr(bufferp, "DIMENSION");
				if (str) {
					// Read the dimensions
					bufferp = findnextnumber(str); // Skip field "Dimension".
					if (*bufferp == '\0') {
						// Read a non-empty line.
						bufferp = readline(buffer, fp, &line_count);
					}
					dimension = (int)strtol(bufferp, &bufferp, 0);
					if (dimension != 2 && dimension != 3) {
						printf("Unknown dimension in file on line %d in file %s\n",
							line_count, infilename);
						fclose(fp);
						return false;
					}
					mesh_dim = dimension;
				}
			}
			if (nverts == 0) {
				// Find if it is the keyword "Vertices".
				str = strstr(bufferp, "Vertices");
				if (!str) str = strstr(bufferp, "vertices");
				if (!str) str = strstr(bufferp, "VERTICES");
				if (str) {
					// Read the number of vertices.
					bufferp = findnextnumber(str); // Skip field "Vertices".
					if (*bufferp == '\0') {
						// Read a non-empty line.
						bufferp = readline(buffer, fp, &line_count);
					}
					nverts = (int)strtol(bufferp, &bufferp, 0);
					// Initialize the smallest index.
					smallestidx = nverts + 1;
					// Allocate memory for 'tetgenio'
					if (nverts > 0) {
						numberofpoints = nverts;
						pointlist = new REAL[nverts * 3];
					}
					// Read the follwoing node list.
					for (i = 0; i < nverts; i++) {
						bufferp = readline(buffer, fp, &line_count);
						if (bufferp == NULL) {
							printf("Unexpected end of file on line %d in file %s\n",
								line_count, infilename);
							fclose(fp);
							return false;
						}
						// Read vertex coordinates
						coord = &pointlist[i * 3];
						for (j = 0; j < 3; j++) {
							if (*bufferp == '\0') {
								printf("Syntax error reading vertex coords on line");
								printf(" %d in file %s\n", line_count, infilename);
								fclose(fp);
								return false;
							}
							if ((j < 2) || (dimension == 3)) {
								coord[j] = (REAL)strtod(bufferp, &bufferp);
							}
							else {
								assert((j == 2) && (dimension == 2));
								coord[j] = 0.0;
							}
							bufferp = findnextnumber(bufferp);
						}
					}
					continue;
				}
			}
			if (ntets == 0) {
				// Find if it is the keyword "Tetrahedra"
				corners = 0;
				str = strstr(bufferp, "Tetrahedra");
				if (!str) str = strstr(bufferp, "tetrahedra");
				if (!str) str = strstr(bufferp, "TETRAHEDRA");
				if (str) {
					corners = 4;
				}
				if (corners == 4) {
					// Read the number of tetrahedra
					bufferp = findnextnumber(str); // Skip field "Tetrahedra".
					if (*bufferp == '\0') {
						// Read a non-empty line.
						bufferp = readline(buffer, fp, &line_count);
					}
					ntets = strtol(bufferp, &bufferp, 0);
					if (ntets > 0) {
						// It is a tetrahedral mesh.
						numberoftetrahedra = ntets;
						numberofcorners = 4;
						numberoftetrahedronattributes = 1;
						tetrahedronlist = new int[ntets * 4];
						tetrahedronattributelist = new REAL[ntets];
					}
				} // if (corners == 4)
				// Read the list of tetrahedra.
				for (i = 0; i < numberoftetrahedra; i++) {
					plist = &(tetrahedronlist[i * 4]);
					bufferp = readline(buffer, fp, &line_count);
					if (bufferp == NULL) {
						printf("Unexpected end of file on line %d in file %s\n",
							line_count, infilename);
						fclose(fp);
						return false;
					}
					// Read the vertices of the tet.
					for (j = 0; j < corners; j++) {
						if (*bufferp == '\0') {
							printf("Syntax error reading face on line %d in file %s\n",
								line_count, infilename);
							fclose(fp);
							return false;
						}
						plist[j] = (int)strtol(bufferp, &bufferp, 0);
						// Remember the smallest index.
						if (plist[j] < smallestidx) smallestidx = plist[j];
						bufferp = findnextnumber(bufferp);
					}
					// Read the attribute of the tet if it exists.
					tetrahedronattributelist[i] = 0;
					if (*bufferp != '\0') {
						tetrahedronattributelist[i] = (REAL)strtol(bufferp, &bufferp, 0);
					}
				} // i
			} // Tetrahedra
			if (nfaces == 0) {
				// Find if it is the keyword "Triangles" or "Quadrilaterals".
				corners = 0;
				str = strstr(bufferp, "Triangles");
				if (!str) str = strstr(bufferp, "triangles");
				if (!str) str = strstr(bufferp, "TRIANGLES");
				if (str) {
					corners = 3;
				}
				else {
					str = strstr(bufferp, "Quadrilaterals");
					if (!str) str = strstr(bufferp, "quadrilaterals");
					if (!str) str = strstr(bufferp, "QUADRILATERALS");
					if (str) {
						corners = 4;
					}
				}
				if (corners == 3 || corners == 4) {
					// Read the number of triangles (or quadrilaterals).
					bufferp = findnextnumber(str); // Skip field "Triangles".
					if (*bufferp == '\0') {
						// Read a non-empty line.
						bufferp = readline(buffer, fp, &line_count);
					}
					nfaces = strtol(bufferp, &bufferp, 0);
					// Allocate memory for 'tetgenio'
					if (nfaces > 0) {
						if (!istetmesh) {
							// It is a PLC surface mesh.
							if (numberoffacets > 0) {
								// facetlist has already been allocated. Enlarge arrays.
								// This happens when the surface mesh contains mixed cells.
								tmpflist = new tetgenio::facet[numberoffacets + nfaces];
								tmpfmlist = new int[numberoffacets + nfaces];
								// Copy the data of old arrays into new arrays.
								for (i = 0; i < numberoffacets; i++) {
									f = &(tmpflist[i]);
									tetgenio::init(f);
									*f = facetlist[i];
									tmpfmlist[i] = facetmarkerlist[i];
								}
								// Release old arrays.
								delete[] facetlist;
								delete[] facetmarkerlist;
								// Remember the new arrays.
								facetlist = tmpflist;
								facetmarkerlist = tmpfmlist;
							}
							else {
								// This is the first time to allocate facetlist.
								facetlist = new tetgenio::facet[nfaces];
								facetmarkerlist = new int[nfaces];
							}
						}
						else {
							if (corners == 3) {
								// It is a surface mesh of a tetrahedral mesh.
								numberoftrifaces = nfaces;
								trifacelist = new int[nfaces * 3];
								trifacemarkerlist = new int[nfaces];
							}
						}
					} // if (nfaces > 0)
					// Read the following list of faces.
					if (!istetmesh) {
						for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
							bufferp = readline(buffer, fp, &line_count);
							if (bufferp == NULL) {
								printf("Unexpected end of file on line %d in file %s\n",
									line_count, infilename);
								fclose(fp);
								return false;
							}
							f = &facetlist[i];
							tetgenio::init(f);
							// In .mesh format, each facet has one polygon, no hole.
							f->numberofpolygons = 1;
							f->polygonlist = new tetgenio::polygon[1];
							p = &f->polygonlist[0];
							tetgenio::init(p);
							p->numberofvertices = corners;
							// Allocate memory for face vertices
							p->vertexlist = new int[p->numberofvertices];
							// Read the vertices of the face.
							for (j = 0; j < corners; j++) {
								if (*bufferp == '\0') {
									printf("Syntax error reading face on line %d in file %s\n",
										line_count, infilename);
									fclose(fp);
									return false;
								}
								p->vertexlist[j] = (int)strtol(bufferp, &bufferp, 0);
								// Remember the smallest index.
								if (p->vertexlist[j] < smallestidx) {
									smallestidx = p->vertexlist[j];
								}
								bufferp = findnextnumber(bufferp);
							}
							// Read the marker of the face if it exists.
							facetmarkerlist[i] = 0;
							if (*bufferp != '\0') {
								facetmarkerlist[i] = (int)strtol(bufferp, &bufferp, 0);
							}
						}
						// Have read in a list of triangles/quads.
						numberoffacets += nfaces;
						nfaces = 0;
					}
					else {
						// It is a surface mesh of a tetrahedral mesh.
						if (corners == 3) {
							for (i = 0; i < numberoftrifaces; i++) {
								plist = &(trifacelist[i * 3]);
								bufferp = readline(buffer, fp, &line_count);
								if (bufferp == NULL) {
									printf("Unexpected end of file on line %d in file %s\n",
										line_count, infilename);
									fclose(fp);
									return false;
								}
								// Read the vertices of the face.
								for (j = 0; j < corners; j++) {
									if (*bufferp == '\0') {
										printf("Syntax error reading face on line %d in file %s\n",
											line_count, infilename);
										fclose(fp);
										return false;
									}
									plist[j] = (int)strtol(bufferp, &bufferp, 0);
									// Remember the smallest index.
									if (plist[j] < smallestidx) {
										smallestidx = plist[j];
									}
									bufferp = findnextnumber(bufferp);
								}
								// Read the marker of the face if it exists.
								trifacemarkerlist[i] = 0;
								if (*bufferp != '\0') {
									trifacemarkerlist[i] = (int)strtol(bufferp, &bufferp, 0);
								}
							} // i
						} // if (corners == 3)
					} // if (b.Refine())
				} // if (corners == 3 || corners == 4)
			}
		}

		// Close file
		fclose(fp);

		// Decide the firstnumber of the index.
		if (smallestidx == 0) {
			firstnumber = 0;
		}
		else if (smallestidx == 1) {
			firstnumber = 1;
		}
		else {
			printf("A wrong smallest index (%d) was detected in file %s\n",
				smallestidx, infilename);
			return false;
		}

		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_vtk()    Load VTK surface mesh from file (.vtk ascii or binary).     //
	//                                                                           //
	// This function is contributed by: Bryn Lloyd, Computer Vision Laboratory,  //
	// ETH, Zuerich. May 7, 2007.                                                //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	// Two functions used in read/write VTK files.

	void swapBytes(unsigned char* var, int size)
	{
		int i = 0;
		int j = size - 1;
		char c;

		while (i < j) {
			c = var[i]; var[i] = var[j]; var[j] = c;
			i++, j--;
		}
	}

	bool testIsBigEndian()
	{
		short word = 0x4321;
		if ((*(char *)& word) != 0x21)
			return true;
		else
			return false;
	}


	bool tetgenio::load_vtk(char* filebasename)
	{
		FILE *fp;
		tetgenio::facet *f;
		tetgenio::polygon *p;
		char infilename[FILENAMESIZE];
		char line[INPUTLINESIZE];
		char mode[128], id[256], fmt[64];
		char *bufferp;
		double *coord;
		float _x, _y, _z;
		int nverts = 0;
		int nfaces = 0;
		int line_count = 0;
		int dummy;
		int id1, id2, id3;
		int nn = -1;
		int nn_old = -1;
		int i, j;
		bool ImALittleEndian = !testIsBigEndian();

		int smallestidx = 0;

		strncpy(infilename, filebasename, FILENAMESIZE - 1);
		infilename[FILENAMESIZE - 1] = '\0';
		if (infilename[0] == '\0') {
			printf("Error:  No filename.\n");
			return false;
		}
		if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) {
			strcat(infilename, ".vtk");
		}
		if (!(fp = fopen(infilename, "r"))) {
			printf("Error:  Unable to open file %s\n", infilename);
			return false;
		}
		printf("Opening %s.\n", infilename);

		// Default uses the index starts from '0'.
		firstnumber = 0;
		strcpy(mode, "BINARY");

		while ((bufferp = readline(line, fp, &line_count)) != NULL) {
			if (strlen(line) == 0) continue;
			//swallow lines beginning with a comment sign or white space
			if (line[0] == '#' || line[0] == '\n' || line[0] == 10 || line[0] == 13 ||
				line[0] == 32) continue;

			sscanf(line, "%s", id);
			if (!strcmp(id, "ASCII")) {
				strcpy(mode, "ASCII");
			}

			if (!strcmp(id, "POINTS")) {
				sscanf(line, "%s %d %s", id, &nverts, fmt);
				if (nverts > 0) {
					numberofpoints = nverts;
					pointlist = new REAL[nverts * 3];
					smallestidx = nverts + 1;
				}

				if (!strcmp(mode, "BINARY")) {
					for (i = 0; i < nverts; i++) {
						coord = &pointlist[i * 3];
						if (!strcmp(fmt, "double")) {
							fread((char*)(&(coord[0])), sizeof(double), 1, fp);
							fread((char*)(&(coord[1])), sizeof(double), 1, fp);
							fread((char*)(&(coord[2])), sizeof(double), 1, fp);
							if (ImALittleEndian){
								swapBytes((unsigned char *)&(coord[0]), sizeof(coord[0]));
								swapBytes((unsigned char *)&(coord[1]), sizeof(coord[1]));
								swapBytes((unsigned char *)&(coord[2]), sizeof(coord[2]));
							}
						}
						else if (!strcmp(fmt, "float")) {
							fread((char*)(&_x), sizeof(float), 1, fp);
							fread((char*)(&_y), sizeof(float), 1, fp);
							fread((char*)(&_z), sizeof(float), 1, fp);
							if (ImALittleEndian){
								swapBytes((unsigned char *)&_x, sizeof(_x));
								swapBytes((unsigned char *)&_y, sizeof(_y));
								swapBytes((unsigned char *)&_z, sizeof(_z));
							}
							coord[0] = double(_x);
							coord[1] = double(_y);
							coord[2] = double(_z);
						}
						else {
							printf("Error: Only float or double formats are supported!\n");
							return false;
						}
					}
				}
				else if (!strcmp(mode, "ASCII")) {
					for (i = 0; i < nverts; i++){
						bufferp = readline(line, fp, &line_count);
						if (bufferp == NULL) {
							printf("Unexpected end of file on line %d in file %s\n",
								line_count, infilename);
							fclose(fp);
							return false;
						}
						// Read vertex coordinates
						coord = &pointlist[i * 3];
						for (j = 0; j < 3; j++) {
							if (*bufferp == '\0') {
								printf("Syntax error reading vertex coords on line");
								printf(" %d in file %s\n", line_count, infilename);
								fclose(fp);
								return false;
							}
							coord[j] = (REAL)strtod(bufferp, &bufferp);
							bufferp = findnextnumber(bufferp);
						}
					}
				}
				continue;
			}

			if (!strcmp(id, "POLYGONS")) {
				sscanf(line, "%s %d  %d", id, &nfaces, &dummy);
				if (nfaces > 0) {
					numberoffacets = nfaces;
					facetlist = new tetgenio::facet[nfaces];
				}

				if (!strcmp(mode, "BINARY")) {
					for (i = 0; i < nfaces; i++){
						fread((char*)(&nn), sizeof(int), 1, fp);
						if (ImALittleEndian){
							swapBytes((unsigned char *)&nn, sizeof(nn));
						}
						if (i == 0)
							nn_old = nn;
						if (nn != nn_old) {
							printf("Error:  No mixed cells are allowed.\n");
							return false;
						}

						if (nn == 3){
							fread((char*)(&id1), sizeof(int), 1, fp);
							fread((char*)(&id2), sizeof(int), 1, fp);
							fread((char*)(&id3), sizeof(int), 1, fp);
							if (ImALittleEndian){
								swapBytes((unsigned char *)&id1, sizeof(id1));
								swapBytes((unsigned char *)&id2, sizeof(id2));
								swapBytes((unsigned char *)&id3, sizeof(id3));
							}
							f = &facetlist[i];
							init(f);
							// In .off format, each facet has one polygon, no hole.
							f->numberofpolygons = 1;
							f->polygonlist = new tetgenio::polygon[1];
							p = &f->polygonlist[0];
							init(p);
							// Set number of vertices
							p->numberofvertices = 3;
							// Allocate memory for face vertices
							p->vertexlist = new int[p->numberofvertices];
							p->vertexlist[0] = id1;
							p->vertexlist[1] = id2;
							p->vertexlist[2] = id3;
							// Detect the smallest index.
							for (j = 0; j < 3; j++) {
								if (p->vertexlist[j] < smallestidx) {
									smallestidx = p->vertexlist[j];
								}
							}
						}
						else {
							printf("Error: Only triangles are supported\n");
							return false;
						}
					}
				}
				else if (!strcmp(mode, "ASCII")) {
					for (i = 0; i < nfaces; i++) {
						bufferp = readline(line, fp, &line_count);
						nn = (int)strtol(bufferp, &bufferp, 0);
						if (i == 0)
							nn_old = nn;
						if (nn != nn_old) {
							printf("Error:  No mixed cells are allowed.\n");
							return false;
						}

						if (nn == 3) {
							bufferp = findnextnumber(bufferp); // Skip the first field.
							id1 = (int)strtol(bufferp, &bufferp, 0);
							bufferp = findnextnumber(bufferp);
							id2 = (int)strtol(bufferp, &bufferp, 0);
							bufferp = findnextnumber(bufferp);
							id3 = (int)strtol(bufferp, &bufferp, 0);
							f = &facetlist[i];
							init(f);
							// In .off format, each facet has one polygon, no hole.
							f->numberofpolygons = 1;
							f->polygonlist = new tetgenio::polygon[1];
							p = &f->polygonlist[0];
							init(p);
							// Set number of vertices
							p->numberofvertices = 3;
							// Allocate memory for face vertices
							p->vertexlist = new int[p->numberofvertices];
							p->vertexlist[0] = id1;
							p->vertexlist[1] = id2;
							p->vertexlist[2] = id3;
							// Detect the smallest index.
							for (j = 0; j < 3; j++) {
								if (p->vertexlist[j] < smallestidx) {
									smallestidx = p->vertexlist[j];
								}
							}
						}
						else {
							printf("Error:  Only triangles are supported.\n");
							return false;
						}
					}
				}

				fclose(fp);

				// Decide the firstnumber of the index.
				if (smallestidx == 0) {
					firstnumber = 0;
				}
				else if (smallestidx == 1) {
					firstnumber = 1;
				}
				else {
					printf("A wrong smallest index (%d) was detected in file %s\n",
						smallestidx, infilename);
					return false;
				}

				return true;
			}

			if (!strcmp(id, "LINES") || !strcmp(id, "CELLS")){
				printf("Warning:  load_vtk(): cannot read formats LINES, CELLS.\n");
			}
		} // while ()

		return true;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// load_plc()    Load a piecewise linear complex from file(s).               //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_plc(char* filebasename, const TetInEnum& ob)
	{
		bool success=false;

		switch (ob)
		{
		case TetInEnum::NODES:
			success = load_node(filebasename);
			break;
		case TetInEnum::POLY:
			success = load_poly(filebasename);			
			break;
		case TetInEnum::OFF:
			success = load_off(filebasename);
			break;
		case TetInEnum::PLY:
			success = load_ply(filebasename);
			break;
		case TetInEnum::STL:
			success = load_stl(filebasename);
			break;
		case TetInEnum::MEDIT:
			success = load_medit(filebasename, 0);
			break;
		case TetInEnum::VTK:
			success = load_vtk(filebasename);
			break;
		default:
			success = load_poly(filebasename);
			break;
		}

		if (success) 
		{
			// Try to load the following files (.edge, .var, .mtr).
			load_edge(filebasename);
			load_var(filebasename);
			load_mtr(filebasename);
		}

		return success;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// loadMesh()    Load a tetrahedral mesh from file(s).                      //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	bool tetgenio::load_tetmesh(char* filebasename, const TetInEnum& object)
	{
		bool success;

		if (object == TetInEnum::MEDIT) {
			success = load_medit(filebasename, 1);
		}
		else {
			success = load_node(filebasename);
			if (success) {
				success = load_tet(filebasename);
			}
			if (success) {
				// Try to load the following files (.face, .edge, .vol).
				load_face(filebasename);
				load_edge(filebasename);
				load_vol(filebasename);
			}
		}

		if (success) {
			// Try to load the following files (.var, .mtr).
			load_var(filebasename);
			load_mtr(filebasename);
		}

		return success;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// save_nodes()    Save points to a .node file.                              //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	void tetgenio::save_nodes(char* filebasename)
	{
		FILE *fout;
		char outnodefilename[FILENAMESIZE];
		char outmtrfilename[FILENAMESIZE];
		int i, j;

		sprintf(outnodefilename, "%s.node", filebasename);
		printf("Saving nodes to %s\n", outnodefilename);
		fout = fopen(outnodefilename, "w");
		fprintf(fout, "%d  %d  %d  %d\n", numberofpoints, mesh_dim,
			numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
		for (i = 0; i < numberofpoints; i++) {
			if (mesh_dim == 2) {
				fprintf(fout, "%d  %.16g  %.16g", i + firstnumber, pointlist[i * 3],
					pointlist[i * 3 + 1]);
			}
			else {
				fprintf(fout, "%d  %.16g  %.16g  %.16g", i + firstnumber,
					pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
			}
			for (j = 0; j < numberofpointattributes; j++) {
				fprintf(fout, "  %.16g",
					pointattributelist[i * numberofpointattributes + j]);
			}
			if (pointmarkerlist != NULL) {
				fprintf(fout, "  %d", pointmarkerlist[i]);
			}
			fprintf(fout, "\n");
		}
		fclose(fout);

		// If the point metrics exist, output them to a .mtr file.
		if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *)NULL)) {
			sprintf(outmtrfilename, "%s.mtr", filebasename);
			printf("Saving metrics to %s\n", outmtrfilename);
			fout = fopen(outmtrfilename, "w");
			fprintf(fout, "%d  %d\n", numberofpoints, numberofpointmtrs);
			for (i = 0; i < numberofpoints; i++) {
				for (j = 0; j < numberofpointmtrs; j++) {
					fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
				}
				fprintf(fout, "\n");
			}
			fclose(fout);
		}
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// save_elements()    Save elements to a .ele file.                          //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	void tetgenio::save_elements(char* filebasename)
	{
		FILE *fout;
		char outelefilename[FILENAMESIZE];
		int i, j;

		sprintf(outelefilename, "%s.ele", filebasename);
		printf("Saving elements to %s\n", outelefilename);
		fout = fopen(outelefilename, "w");
		if (mesh_dim == 3) {
			fprintf(fout, "%d  %d  %d\n", numberoftetrahedra, numberofcorners,
				numberoftetrahedronattributes);
			for (i = 0; i < numberoftetrahedra; i++) {
				fprintf(fout, "%d", i + firstnumber);
				for (j = 0; j < numberofcorners; j++) {
					fprintf(fout, "  %5d", tetrahedronlist[i * numberofcorners + j]);
				}
				for (j = 0; j < numberoftetrahedronattributes; j++) {
					fprintf(fout, "  %g",
						tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
				}
				fprintf(fout, "\n");
			}
		}
		else {
			// Save a two-dimensional mesh.
			fprintf(fout, "%d  %d  %d\n", numberoftrifaces, 3, trifacemarkerlist ? 1 : 0);
			for (i = 0; i < numberoftrifaces; i++) {
				fprintf(fout, "%d", i + firstnumber);
				for (j = 0; j < 3; j++) {
					fprintf(fout, "  %5d", trifacelist[i * 3 + j]);
				}
				if (trifacemarkerlist != NULL) {
					fprintf(fout, "  %d", trifacemarkerlist[i]);
				}
				fprintf(fout, "\n");
			}
		}

		fclose(fout);
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// save_faces()    Save faces to a .face file.                               //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	void tetgenio::save_faces(char* filebasename)
	{
		FILE *fout;
		char outfacefilename[FILENAMESIZE];
		int i;

		sprintf(outfacefilename, "%s.face", filebasename);
		printf("Saving faces to %s\n", outfacefilename);
		fout = fopen(outfacefilename, "w");
		fprintf(fout, "%d  %d\n", numberoftrifaces,
			trifacemarkerlist != NULL ? 1 : 0);
		for (i = 0; i < numberoftrifaces; i++) {
			fprintf(fout, "%d  %5d  %5d  %5d", i + firstnumber, trifacelist[i * 3],
				trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
			if (trifacemarkerlist != NULL) {
				fprintf(fout, "  %d", trifacemarkerlist[i]);
			}
			fprintf(fout, "\n");
		}

		fclose(fout);
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// save_edges()    Save egdes to a .edge file.                               //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	void tetgenio::save_edges(char* filebasename)
	{
		FILE *fout;
		char outedgefilename[FILENAMESIZE];
		int i;

		sprintf(outedgefilename, "%s.edge", filebasename);
		printf("Saving edges to %s\n", outedgefilename);
		fout = fopen(outedgefilename, "w");
		fprintf(fout, "%d  %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
		for (i = 0; i < numberofedges; i++) {
			fprintf(fout, "%d  %4d  %4d", i + firstnumber, edgelist[i * 2],
				edgelist[i * 2 + 1]);
			if (edgemarkerlist != NULL) {
				fprintf(fout, "  %d", edgemarkerlist[i]);
			}
			fprintf(fout, "\n");
		}

		fclose(fout);
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// save_neighbors()    Save egdes to a .neigh file.                          //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	void tetgenio::save_neighbors(char* filebasename)
	{
		FILE *fout;
		char outneighborfilename[FILENAMESIZE];
		int i;

		sprintf(outneighborfilename, "%s.neigh", filebasename);
		printf("Saving neighbors to %s\n", outneighborfilename);
		fout = fopen(outneighborfilename, "w");
		fprintf(fout, "%d  %d\n", numberoftetrahedra, mesh_dim + 1);
		for (i = 0; i < numberoftetrahedra; i++) {
			if (mesh_dim == 2) {
				fprintf(fout, "%d  %5d  %5d  %5d", i + firstnumber, neighborlist[i * 3],
					neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
			}
			else {
				fprintf(fout, "%d  %5d  %5d  %5d  %5d", i + firstnumber,
					neighborlist[i * 4], neighborlist[i * 4 + 1],
					neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
			}
			fprintf(fout, "\n");
		}

		fclose(fout);
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// save_poly()    Save segments or facets to a .poly file.                   //
	//                                                                           //
	// It only save the facets, holes and regions. No .node file is saved.       //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	void tetgenio::save_poly(char* filebasename)
	{
		FILE *fout;
		facet *f;
		polygon *p;
		char outpolyfilename[FILENAMESIZE];
		int i, j, k;

		sprintf(outpolyfilename, "%s.poly", filebasename);
		printf("Saving poly to %s\n", outpolyfilename);
		fout = fopen(outpolyfilename, "w");

		// The zero indicates that the vertices are in a separate .node file.
		//   Followed by number of dimensions, number of vertex attributes,
		//   and number of boundary markers (zero or one).
		fprintf(fout, "%d  %d  %d  %d\n", 0, mesh_dim, numberofpointattributes,
			pointmarkerlist != NULL ? 1 : 0);

		// Save segments or facets.
		if (mesh_dim == 2) {
			// Number of segments, number of boundary markers (zero or one).
			fprintf(fout, "%d  %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
			for (i = 0; i < numberofedges; i++) {
				fprintf(fout, "%d  %4d  %4d", i + firstnumber, edgelist[i * 2],
					edgelist[i * 2 + 1]);
				if (edgemarkerlist != NULL) {
					fprintf(fout, "  %d", edgemarkerlist[i]);
				}
				fprintf(fout, "\n");
			}
		}
		else {
			// Number of facets, number of boundary markers (zero or one).
			fprintf(fout, "%d  %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
			for (i = 0; i < numberoffacets; i++) {
				f = &(facetlist[i]);
				fprintf(fout, "%d  %d  %d  # %d\n", f->numberofpolygons, f->numberofholes,
					facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
				// Output polygons of this facet.
				for (j = 0; j < f->numberofpolygons; j++) {
					p = &(f->polygonlist[j]);
					fprintf(fout, "%d  ", p->numberofvertices);
					for (k = 0; k < p->numberofvertices; k++) {
						if (((k + 1) % 10) == 0) {
							fprintf(fout, "\n  ");
						}
						fprintf(fout, "  %d", p->vertexlist[k]);
					}
					fprintf(fout, "\n");
				}
				// Output holes of this facet.
				for (j = 0; j < f->numberofholes; j++) {
					fprintf(fout, "%d  %.12g  %.12g  %.12g\n", j + firstnumber,
						f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
				}
			}
		}

		// Save holes.
		fprintf(fout, "%d\n", numberofholes);
		for (i = 0; i < numberofholes; i++) {
			// Output x, y coordinates.
			fprintf(fout, "%d  %.12g  %.12g", i + firstnumber, holelist[i * mesh_dim],
				holelist[i * mesh_dim + 1]);
			if (mesh_dim == 3) {
				// Output z coordinate.
				fprintf(fout, "  %.12g", holelist[i * mesh_dim + 2]);
			}
			fprintf(fout, "\n");
		}

		// Save regions.
		fprintf(fout, "%d\n", numberofregions);
		for (i = 0; i < numberofregions; i++) {
			if (mesh_dim == 2) {
				// Output the index, x, y coordinates, attribute (region number)
				//   and maximum area constraint (maybe -1).
				fprintf(fout, "%d  %.12g  %.12g  %.12g  %.12g\n", i + firstnumber,
					regionlist[i * 4], regionlist[i * 4 + 1],
					regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
			}
			else {
				// Output the index, x, y, z coordinates, attribute (region number)
				//   and maximum volume constraint (maybe -1).
				fprintf(fout, "%d  %.12g  %.12g  %.12g  %.12g  %.12g\n", i + firstnumber,
					regionlist[i * 5], regionlist[i * 5 + 1],
					regionlist[i * 5 + 2], regionlist[i * 5 + 3],
					regionlist[i * 5 + 4]);
			}
		}

		fclose(fout);
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// save_faces2smesh()    Save triangular faces to a .smesh file.             //
	//                                                                           //
	// It only save the facets. No holes and regions. No .node file.             //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	void tetgenio::save_faces2smesh(char* filebasename)
	{
		FILE *fout;
		char outsmeshfilename[FILENAMESIZE];
		int i, j;

		sprintf(outsmeshfilename, "%s.smesh", filebasename);
		printf("Saving faces to %s\n", outsmeshfilename);
		fout = fopen(outsmeshfilename, "w");

		// The zero indicates that the vertices are in a separate .node file.
		//   Followed by number of dimensions, number of vertex attributes,
		//   and number of boundary markers (zero or one).
		fprintf(fout, "%d  %d  %d  %d\n", 0, mesh_dim, numberofpointattributes,
			pointmarkerlist != NULL ? 1 : 0);

		// Number of facets, number of boundary markers (zero or one).
		fprintf(fout, "%d  %d\n", numberoftrifaces,
			trifacemarkerlist != NULL ? 1 : 0);

		// Output triangular facets.
		for (i = 0; i < numberoftrifaces; i++) {
			j = i * 3;
			fprintf(fout, "3  %d %d %d", trifacelist[j], trifacelist[j + 1],
				trifacelist[j + 2]);
			if (trifacemarkerlist != NULL) {
				fprintf(fout, "  %d", trifacemarkerlist[i]);
			}
			fprintf(fout, "\n");
		}

		// No holes and regions.
		fprintf(fout, "0\n");
		fprintf(fout, "0\n");

		fclose(fout);
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// readline()   Read a nonempty line from a file.                            //
	//                                                                           //
	// A line is considered "nonempty" if it contains something more than white  //
	// spaces.  If a line is considered empty, it will be dropped and the next   //
	// line will be read, this process ends until reaching the end-of-file or a  //
	// non-empty line.  Return NULL if it is the end-of-file, otherwise, return  //
	// a pointer to the first non-whitespace character of the line.              //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
	{
		char *result;

		// Search for a non-empty line.
		do {
			result = fgets(string, INPUTLINESIZE - 1, infile);
			if (linenumber) (*linenumber)++;
			if (result == (char *)NULL) {
				return (char *)NULL;
			}
			// Skip white spaces.
			while ((*result == ' ') || (*result == '\t')) result++;
			// If it's end of line, read another line and try again.
		} while ((*result == '\0') || (*result == '\r') || (*result == '\n'));
		return result;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// findnextfield()   Find the next field of a string.                        //
	//                                                                           //
	// Jumps past the current field by searching for whitespace or a comma, then //
	// jumps past the whitespace or the comma to find the next field.            //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	char* tetgenio::findnextfield(char *string)
	{
		char *result;

		result = string;
		// Skip the current field.  Stop upon reaching whitespace or a comma.
		while ((*result != '\0') && (*result != ' ') && (*result != '\t') &&
			(*result != ',') && (*result != ';')) {
			result++;
		}
		// Now skip the whitespace or the comma, stop at anything else that looks
		//   like a character, or the end of a line. 
		while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
			(*result == ';')) {
			result++;
		}
		return result;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// readnumberline()   Read a nonempty number line from a file.               //
	//                                                                           //
	// A line is considered "nonempty" if it contains something that looks like  //
	// a number.  Comments (prefaced by `#') are ignored.                        //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
	{
		char *result;

		// Search for something that looks like a number.
		do {
			result = fgets(string, INPUTLINESIZE, infile);
			if (result == (char *)NULL) {
				return result;
			}
			// Skip anything that doesn't look like a number, a comment, 
			//   or the end of a line. 
			while ((*result != '\0') && (*result != '#')
				&& (*result != '.') && (*result != '+') && (*result != '-')
				&& ((*result < '0') || (*result > '9'))) {
				result++;
			}
			// If it's a comment or end of line, read another line and try again.
		} while ((*result == '#') || (*result == '\0'));
		return result;
	}

	///////////////////////////////////////////////////////////////////////////////
	//                                                                           //
	// findnextnumber()   Find the next field of a number string.                //
	//                                                                           //
	// Jumps past the current field by searching for whitespace or a comma, then //
	// jumps past the whitespace or the comma to find the next field that looks  //
	// like a number.                                                            //
	//                                                                           //
	///////////////////////////////////////////////////////////////////////////////

	char* tetgenio::findnextnumber(char *string)
	{
		char *result;

		result = string;
		// Skip the current field.  Stop upon reaching whitespace or a comma.
		while ((*result != '\0') && (*result != '#') && (*result != ' ') &&
			(*result != '\t') && (*result != ',')) {
			result++;
		}
		// Now skip the whitespace and anything else that doesn't look like a
		//   number, a comment, or the end of a line. 
		while ((*result != '\0') && (*result != '#')
			&& (*result != '.') && (*result != '+') && (*result != '-')
			&& ((*result < '0') || (*result > '9'))) {
			result++;
		}
		// Check for a comment (prefixed with `#').
		if (*result == '#') {
			*result = '\0';
		}
		return result;
	}
}